Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem 8e7a288bb4 wasm: use wasip1 API for parameter/env passing
Instead of hardcoding the command line parameters and the environment
variables in the binary, pass them at runtime to Node.js and use the
WASIp1 API to retrieve them in wasm_exec.js.

The only real benefit right now is that it becomes possible to change
`go.argv` and `go.env` before running a wasm binary.

This also changes the syscall package for GOOS=js: it now becomes more
like a libc (using wasi-libc), which means error values like
`syscall.EEXIST` will actually match the one returned by the relevant
libc function.

Wasm binary size for packages that import the os package will be
increased somewhat.
2024-10-30 11:14:18 +01:00
347 changed files with 3419 additions and 8576 deletions
+7 -9
View File
@@ -10,12 +10,12 @@ commands:
steps: steps:
- restore_cache: - restore_cache:
keys: keys:
- llvm-source-19-v1 - llvm-source-18-v1
- run: - run:
name: "Fetch LLVM source" name: "Fetch LLVM source"
command: make llvm-source command: make llvm-source
- save_cache: - save_cache:
key: llvm-source-19-v1 key: llvm-source-18-v1
paths: paths:
- llvm-project/clang/lib/Headers - llvm-project/clang/lib/Headers
- llvm-project/clang/include - llvm-project/clang/include
@@ -90,8 +90,6 @@ commands:
name: Check Go code formatting name: Check Go code formatting
command: make fmt-check lint command: make fmt-check lint
- run: make gen-device -j4 - run: make gen-device -j4
# TODO: change this to -skip='TestErrors|TestWasm' with Go 1.20
- run: go test -tags=llvm<<parameters.llvm>> -short -run='TestBuild|TestTest|TestGetList|TestTraceback'
- run: make smoketest XTENSA=0 - run: make smoketest XTENSA=0
- save_cache: - save_cache:
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }} key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
@@ -109,12 +107,12 @@ jobs:
# "make lint" fails before go 1.21 because internal/tools/go.mod specifies packages that require go 1.21 # "make lint" fails before go 1.21 because internal/tools/go.mod specifies packages that require go 1.21
fmt-check: false fmt-check: false
resource_class: large resource_class: large
test-llvm19-go124: test-llvm18-go123:
docker: docker:
- image: golang:1.24-bullseye - image: golang:1.23-bullseye
steps: steps:
- test-linux: - test-linux:
llvm: "19" llvm: "18"
resource_class: large resource_class: large
workflows: workflows:
@@ -123,5 +121,5 @@ workflows:
# This tests our lowest supported versions of Go and LLVM, to make sure at # This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass. # least the smoke tests still pass.
- test-llvm15-go119 - test-llvm15-go119
# This tests LLVM 19 support when linking against system libraries. # This tests LLVM 18 support when linking against system libraries.
- test-llvm19-go124 - test-llvm18-go123
+10 -13
View File
@@ -33,19 +33,16 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-${{ matrix.os }}-v1 key: llvm-source-18-${{ matrix.os }}-v2
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -70,7 +67,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-19-${{ matrix.os }}-v1 key: llvm-build-18-${{ matrix.os }}-v3
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -107,7 +104,7 @@ jobs:
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test run: make tinygo-test
- name: Make release artifact - name: Make release artifact
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact - name: Publish release artifact
# Note: this release artifact is double-zipped, see: # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39 # https://github.com/actions/upload-artifact/issues/39
@@ -117,8 +114,8 @@ jobs:
# We're doing the former here, to keep artifact uploads fast. # We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: darwin-${{ matrix.goarch }}-double-zipped
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Smoke tests - name: Smoke tests
run: make smoketest TINYGO=$(PWD)/build/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew: test-macos-homebrew:
@@ -126,7 +123,7 @@ jobs:
runs-on: macos-latest runs-on: macos-latest
strategy: strategy:
matrix: matrix:
version: [16, 17, 18, 19] version: [16, 17, 18]
steps: steps:
- name: Set up Homebrew - name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master uses: Homebrew/actions/setup-homebrew@master
@@ -143,15 +140,15 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }} run: go install -tags=llvm${{ matrix.version }}
- name: Check binary - name: Check binary
run: tinygo version run: tinygo version
- name: Build TinyGo (default LLVM) - name: Build TinyGo (default LLVM)
if: matrix.version == 19 if: matrix.version == 18
run: go install run: go install
- name: Check binary - name: Check binary
if: matrix.version == 19 if: matrix.version == 18
run: tinygo version run: tinygo version
+27 -35
View File
@@ -18,9 +18,7 @@ jobs:
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.24-alpine image: golang:1.23-alpine
outputs:
version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Install apk dependencies - name: Install apk dependencies
# tar: needed for actions/cache@v4 # tar: needed for actions/cache@v4
@@ -34,9 +32,6 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Cache Go - name: Cache Go
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
@@ -48,7 +43,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-linux-alpine-v1 key: llvm-source-18-linux-alpine-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -73,7 +68,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-19-linux-alpine-v1 key: llvm-build-18-linux-alpine-v2
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -125,15 +120,15 @@ jobs:
- name: Build TinyGo release - name: Build TinyGo release
run: | run: |
make release deb -j3 STATIC=1 make release deb -j3 STATIC=1
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb cp -p build/release.deb /tmp/tinygo_amd64.deb
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ steps.version.outputs.version }} name: linux-amd64-double-zipped
path: | path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz /tmp/tinygo.linux-amd64.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb /tmp/tinygo_amd64.deb
test-linux-build: test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests. # Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -146,22 +141,22 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
with: with:
version: "29.0.1" version: "19.0.1"
- name: Install wasm-tools - name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Download release artifact - name: Download release artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-amd64-double-zipped
- name: Extract release tarball - name: Extract release tarball
run: | run: |
mkdir -p ~/lib mkdir -p ~/lib
tar -C ~/lib -xf tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- run: make tinygo-test-wasip1-fast - run: make tinygo-test-wasip1-fast
- run: make tinygo-test-wasip2-fast - run: make tinygo-test-wasip2-fast
@@ -189,7 +184,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@@ -198,14 +193,14 @@ jobs:
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
with: with:
version: "29.0.1" version: "19.0.1"
- name: Setup `wasm-tools` - name: Setup `wasm-tools`
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-linux-asserts-v1 key: llvm-source-18-linux-asserts-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -230,7 +225,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-19-linux-asserts-v1 key: llvm-build-18-linux-asserts-v2
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -297,14 +292,11 @@ jobs:
- goarch: arm - goarch: arm
toolchain: arm-linux-gnueabihf toolchain: arm-linux-gnueabihf
libc: armhf libc: armhf
runs-on: ubuntu-22.04 # note: use the oldest image available! (see above) runs-on: ubuntu-20.04
needs: build-linux needs: build-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Get TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install apt dependencies - name: Install apt dependencies
run: | run: |
sudo apt-get update sudo apt-get update
@@ -315,13 +307,13 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-linux-v1 key: llvm-source-18-linux-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -346,7 +338,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-19-linux-${{ matrix.goarch }}-v3 key: llvm-build-18-linux-${{ matrix.goarch }}-v2
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -389,11 +381,11 @@ jobs:
- name: Download amd64 release - name: Download amd64 release
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-amd64-double-zipped
- name: Extract amd64 release - name: Extract amd64 release
run: | run: |
mkdir -p build/release mkdir -p build/release
tar -xf tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz -C build/release tinygo tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
- name: Modify release - name: Modify release
run: | run: |
cp -p build/tinygo build/release/tinygo/bin cp -p build/tinygo build/release/tinygo/bin
@@ -401,12 +393,12 @@ jobs:
- name: Create ${{ matrix.goarch }} release - name: Create ${{ matrix.goarch }} release
run: | run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }} make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: linux-${{ matrix.goarch }}-double-zipped
path: | path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb /tmp/tinygo_${{ matrix.libc }}.deb
+2 -2
View File
@@ -35,8 +35,8 @@ jobs:
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: | images: |
tinygo/llvm-19 tinygo/llvm-18
ghcr.io/${{ github.repository_owner }}/llvm-19 ghcr.io/${{ github.repository_owner }}/llvm-18
tags: | tags: |
type=sha,format=long type=sha,format=long
type=raw,value=latest type=raw,value=latest
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-linux-nix-v1 key: llvm-source-18-linux-nix-v1
path: | path: |
llvm-project/compiler-rt llvm-project/compiler-rt
- name: Download LLVM source - name: Download LLVM source
+5 -5
View File
@@ -2,11 +2,11 @@
# still works after checking out the dev branch (that is, when going from LLVM # 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). # 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' | sudo tee /etc/apt/sources.list.d/llvm.list echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-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 - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update sudo apt-get update
sudo apt-get install --no-install-recommends -y \ sudo apt-get install --no-install-recommends -y \
llvm-19-dev \ llvm-18-dev \
clang-19 \ clang-18 \
libclang-19-dev \ libclang-18-dev \
lld-19 lld-18
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
uses: actions/cache@v4 uses: actions/cache@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-sizediff-v1 key: llvm-source-18-sizediff-v1
path: | path: |
llvm-project/compiler-rt llvm-project/compiler-rt
- name: Download LLVM source - name: Download LLVM source
@@ -1,4 +0,0 @@
#!/bin/sh
# Extract the version string from the source code, to be stored in a variable.
grep 'const version' goenv/version.go | sed 's/^const version = "\(.*\)"$/version=\1/g'
+17 -30
View File
@@ -14,8 +14,6 @@ concurrency:
jobs: jobs:
build-windows: build-windows:
runs-on: windows-2022 runs-on: windows-2022
outputs:
version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Configure pagefile - name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4 uses: al-cheb/configure-pagefile-action@v1.4
@@ -34,20 +32,16 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Extract TinyGo version
id: version
shell: bash
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Restore cached LLVM source - name: Restore cached LLVM source
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-19-windows-v1 key: llvm-source-18-windows-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -72,7 +66,7 @@ jobs:
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-19-windows-v1 key: llvm-build-18-windows-v2
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -100,16 +94,9 @@ jobs:
- name: Build wasi-libc - name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true' if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc run: make wasi-libc
- name: Cache Go cache
uses: actions/cache@v4
with:
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
path: |
C:/Users/runneradmin/AppData/Local/go-build
C:/Users/runneradmin/go/pkg/mod
- name: Install wasmtime - name: Install wasmtime
run: | run: |
scoop install wasmtime@29.0.1 scoop install wasmtime@14.0.4
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make -j3 gen-device
- name: Test TinyGo - name: Test TinyGo
@@ -121,7 +108,7 @@ jobs:
- name: Make release artifact - name: Make release artifact
shell: bash shell: bash
working-directory: build/release working-directory: build/release
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo run: 7z -tzip a release.zip tinygo
- name: Publish release artifact - name: Publish release artifact
# Note: this release artifact is double-zipped, see: # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39 # https://github.com/actions/upload-artifact/issues/39
@@ -131,8 +118,8 @@ jobs:
# We're doing the former here, to keep artifact uploads fast. # We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ steps.version.outputs.version }} name: windows-amd64-double-zipped
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip path: build/release/release.zip
smoke-test-windows: smoke-test-windows:
runs-on: windows-2022 runs-on: windows-2022
@@ -156,17 +143,17 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Smoke tests - name: Smoke tests
shell: bash shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -186,17 +173,17 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -216,22 +203,22 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop install binaryen && scoop install wasmtime@29.0.1 scoop install binaryen && scoop install wasmtime@14.0.4
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24' go-version: '1.23'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Test stdlib packages on wasip1 - name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
-4
View File
@@ -37,9 +37,5 @@ test.exe
test.gba test.gba
test.hex test.hex
test.nro test.nro
test.uf2
test.wasm test.wasm
wasm.wasm wasm.wasm
*.uf2
*.elf
-68
View File
@@ -1,71 +1,3 @@
0.35.0
---
* **general**
- update cmsis-svd library
- use default UART settings in the echo example
- `goenv`: also show git hash with custom build of TinyGo
- `goenv`: support parsing development versions of Go
- `main`: parse extldflags early so we can report the error message
* **compiler**
- `builder`: whitelist temporary directory env var for Clang invocation to fix Windows bug
- `builder`: fix cache paths in `-size=full` output
- `builder`: work around incorrectly escaped DWARF paths on Windows (Clang bug)
- `builder`: fix wasi-libc path names on Windows with `-size=full`
- `builder`: write HTML size report
- `cgo`: support C identifiers only referred to from within macros
- `cgo`: support function-like macros
- `cgo`: support errno value as second return parameter
- `cgo`: add support for `#cgo noescape` lines
- `compiler`: fix bug in interrupt lowering
- `compiler`: allow panic directly in `defer`
- `compiler`: fix wasmimport -> wasmexport in error message
- `compiler`: support `//go:noescape` pragma
- `compiler`: report error instead of crashing when instantiating a generic function without body
- `interp`: align created globals
* **standard library**
- `machine`: modify i2s interface/implementation to better match specification
- `os`: implement `StartProcess`
- `reflect`: add `Value.Clear`
- `reflect`: add interface support to `NumMethods`
- `reflect`: fix `AssignableTo` for named + non-named types
- `reflect`: implement `CanConvert`
- `reflect`: handle more cases in `Convert`
- `reflect`: fix Copy of non-pointer array with size > 64bits
- `runtime`: don't call sleepTicks with a negative duration
- `runtime`: optimize GC scanning (findHead)
- `runtime`: move constants into shared package
- `runtime`: add `runtime.fcntl` function for internal/syscall/unix
- `runtime`: heapptr only needs to be initialized once
- `runtime`: refactor scheduler (this fixes a few bugs with `-scheduler=none`)
- `runtime`: rewrite channel implementation to be smaller and more flexible
- `runtime`: use `SA_RESTART` when registering a signal for os/signal
- `runtime`: implement race-free signals using futexes
- `runtime`: run deferred functions in `Goexit`
- `runtime`: remove `Cond` which seems to be unused
- `runtime`: properly handle unix read on directory
- `runtime/trace`: stub all public methods
- `sync`: don't use volatile in `Mutex`
- `sync`: implement `WaitGroup` using a (pseudo)futex
- `sync`: make `Cond` parallelism-safe
- `syscall`: use wasi-libc tables for wasm/js target
* **targets**
- `mips`: fix a bug when scanning the stack
- `nintendoswitch`: get this target to compile again
- `rp2350`: add support for the new RP2350
- `rp2040/rp2350` : make I2C implementation shared for rp2040/rp2350
- `rp2040/rp2350` : make SPI implementation shared for rp2040/rp2350
- `rp2040/rp2350` : make RNG implementation shared for rp2040/rp2350
- `wasm`: revise and simplify wasmtime argument handling
- `wasm`: support `//go:wasmexport` functions after a call to `time.Sleep`
- `wasm`: correctly return from run() in wasm_exec.js
- `wasm`: call process.exit() when go.run() returns
- `windows`: don't return, exit via exit(0) instead to flush stdout buffer
* **boards**
- add support for the Tillitis TKey
- add support for the Raspberry Pi Pico2 (based on the RP2040)
- add support for Pimoroni Tiny2350
0.34.0 0.34.0
--- ---
* **general** * **general**
+2 -2
View File
@@ -1,5 +1,5 @@
# tinygo-llvm stage obtains the llvm source for TinyGo # tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.24 AS tinygo-llvm FROM golang:1.23 AS tinygo-llvm
RUN apt-get update && \ 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 && \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without # tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc). # all the build tools etc).
FROM golang:1.24 AS tinygo-compiler FROM golang:1.23 AS tinygo-compiler
# Copy tinygo build. # Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+15 -41
View File
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools. # Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order. # Versions are listed here in descending priority order.
LLVM_VERSIONS = 19 18 17 16 15 LLVM_VERSIONS = 18 17 16 15
errifempty = $(if $(1),$(1),$(error $(2))) 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))) 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) toolSearchPathsVersion = $(1)-$(2)
@@ -147,7 +147,7 @@ endif
MD5SUM ?= md5sum MD5SUM ?= md5sum
# Libraries that should be linked in for the statically linked Clang. # Libraries that should be linked in for the statically linked Clang.
CLANG_LIB_NAMES = clangAnalysis clangAPINotes clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangInstallAPI 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++ CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
# Libraries that should be linked in for the statically linked LLD. # Libraries that should be linked in for the statically linked LLD.
@@ -238,7 +238,7 @@ gen-device-renesas: build/gen-device-svd
GO111MODULE=off $(GO) fmt ./src/device/renesas GO111MODULE=off $(GO) fmt ./src/device/renesas
$(LLVM_PROJECTDIR)/llvm: $(LLVM_PROJECTDIR)/llvm:
git clone -b xtensa_release_19.1.2 --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 ## Get LLVM sources llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources
# Configure LLVM. # Configure LLVM.
@@ -291,7 +291,7 @@ endif
tinygo: ## Build the TinyGo compiler tinygo: ## Build the TinyGo compiler
@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 @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" . 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 test: wasi-libc check-nodejs-version
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS) CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
@@ -309,9 +309,11 @@ TEST_PACKAGES_FAST = \
container/heap \ container/heap \
container/list \ container/list \
container/ring \ container/ring \
crypto/des \
crypto/ecdsa \ crypto/ecdsa \
crypto/elliptic \ crypto/elliptic \
crypto/md5 \ crypto/md5 \
crypto/rc4 \
crypto/sha1 \ crypto/sha1 \
crypto/sha256 \ crypto/sha256 \
crypto/sha512 \ crypto/sha512 \
@@ -353,16 +355,21 @@ TEST_PACKAGES_FAST = \
unique \ unique \
$(nil) $(nil)
# Assume this will go away before Go2, so only check minor version.
ifeq ($(filter $(shell $(GO) env GOVERSION | cut -f 2 -d.), 16 17 18), )
TEST_PACKAGES_FAST += crypto/internal/nistec/fiat
else
TEST_PACKAGES_FAST += crypto/elliptic/internal/fiat
endif
# archive/zip requires os.ReadAt, which is not yet supported on windows # archive/zip requires os.ReadAt, which is not yet supported on windows
# bytes requires mmap # bytes requires mmap
# compress/flate appears to hang on wasi # compress/flate appears to hang on wasi
# crypto/aes fails on wasi, needs panic()/recover() # crypto/aes fails on wasi, needs panic()/recover()
# crypto/des fails on wasi, needs panic()/recover()
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic # crypto/hmac fails on wasi, it exits with a "slice out of range" panic
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows # debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# image requires recover(), which is not yet supported on wasi # image requires recover(), which is not yet supported on wasi
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi # io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# math/bits: needs panic()/recover()
# mime: fail on wasi; neds panic()/recover() # mime: fail on wasi; neds panic()/recover()
# mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK # mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK
# mime/quotedprintable requires syscall.Faccessat # mime/quotedprintable requires syscall.Faccessat
@@ -379,15 +386,11 @@ TEST_PACKAGES_LINUX := \
archive/zip \ archive/zip \
compress/flate \ compress/flate \
crypto/aes \ crypto/aes \
crypto/des \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
encoding/binary \
go/constant \
image \ image \
io/ioutil \ io/ioutil \
math/bits \
mime \ mime \
mime/multipart \ mime/multipart \
mime/quotedprintable \ mime/quotedprintable \
@@ -402,14 +405,10 @@ TEST_PACKAGES_LINUX := \
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX) TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
# os/user requires t.Skip() support
TEST_PACKAGES_WINDOWS := \ TEST_PACKAGES_WINDOWS := \
compress/flate \ compress/flate \
crypto/des \
crypto/hmac \ crypto/hmac \
encoding/binary \ os/user \
go/constant \
math/bits \
strconv \ strconv \
text/template/parse \ text/template/parse \
$(nil) $(nil)
@@ -524,8 +523,6 @@ smoketest: testchdir
# regression test for #2563 # regression test for #2563
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
# test all examples (except pwm) # test all examples (except pwm)
$(TINYGO) build -size short -o test.hex -target=pga2350 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc $(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
@@ -744,14 +741,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo $(TINYGO) build -size short -o test.hex -target=thumby examples/echo
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico2 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=tiny2350 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
@$(MD5SUM) test.hex
# test pwm # test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -833,8 +822,6 @@ endif
ifneq ($(XTENSA), 0) ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1 $(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest $(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
@@ -866,16 +853,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1 $(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=tkey examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=elecrow-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=elecrow-rp2350 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hw-651 examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hw-651-s110v8 examples/machinetest
@$(MD5SUM) test.hex
ifneq ($(WASM), 0) 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/export
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main $(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
@@ -890,7 +867,7 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo $(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -o test.nro -target=nintendoswitch examples/echo2 $(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
@$(MD5SUM) test.nro @$(MD5SUM) test.nro
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go $(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -949,7 +926,6 @@ endif
@cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/fcntl build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src @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/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
@@ -958,7 +934,6 @@ endif
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/misc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
@@ -966,7 +941,6 @@ endif
@cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/process build/release/tinygo/lib/musl/src
@cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt @cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common @cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common @cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
+10 -69
View File
@@ -61,10 +61,6 @@ type BuildResult struct {
// correctly printing test results: the import path isn't always the same as // correctly printing test results: the import path isn't always the same as
// the path listed on the command line. // the path listed on the command line.
ImportPath string ImportPath string
// Map from path to package name. It is needed to attribute binary size to
// the right Go package.
PackagePathMap map[string]string
} }
// packageAction is the struct that is serialized to JSON and hashed, to work as // packageAction is the struct that is serialized to JSON and hashed, to work as
@@ -246,12 +242,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
return result, err return result, err
} }
// Store which filesystem paths map to which package name.
result.PackagePathMap = make(map[string]string, len(lprogram.Packages))
for _, pkg := range lprogram.Sorted() {
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
}
// Create the *ssa.Program. This does not yet build the entire SSA of the // Create the *ssa.Program. This does not yet build the entire SSA of the
// program so it's pretty fast and doesn't need to be parallelized. // program so it's pretty fast and doesn't need to be parallelized.
program := lprogram.LoadSSA() program := lprogram.LoadSSA()
@@ -604,11 +594,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}, },
} }
// Create the output directory, if needed
if err := os.MkdirAll(filepath.Dir(outpath), 0777); err != nil {
return result, err
}
// Check whether we only need to create an object file. // Check whether we only need to create an object file.
// If so, we don't need to link anything and will be finished quickly. // If so, we don't need to link anything and will be finished quickly.
outext := filepath.Ext(outpath) outext := filepath.Ext(outpath)
@@ -672,16 +657,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
ldflags = append(ldflags, "--no-entry") ldflags = append(ldflags, "--no-entry")
} }
if config.Options.BuildMode == "wasi-legacy" {
if !strings.HasPrefix(config.Triple(), "wasm32-") {
return result, fmt.Errorf("buildmode wasi-legacy is only supported on wasm")
}
if config.Options.Scheduler != "none" {
return result, fmt.Errorf("buildmode wasi-legacy only supports scheduler=none")
}
}
// Add compiler-rt dependency if needed. Usually this is a simple load from // Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache. // a cache.
if config.Target.RTLib == "compiler-rt" { if config.Target.RTLib == "compiler-rt" {
@@ -715,7 +690,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
for _, pkg := range lprogram.Sorted() { for _, pkg := range lprogram.Sorted() {
pkg := pkg pkg := pkg
for _, filename := range pkg.CFiles { for _, filename := range pkg.CFiles {
abspath := filepath.Join(pkg.OriginalDir(), filename) abspath := filepath.Join(pkg.Dir, filename)
job := &compileJob{ job := &compileJob{
description: "compile CGo file " + abspath, description: "compile CGo file " + abspath,
run: func(job *compileJob) error { run: func(job *compileJob) error {
@@ -837,12 +812,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
return fmt.Errorf("could not modify stack sizes: %w", err) return fmt.Errorf("could not modify stack sizes: %w", err)
} }
} }
// Apply patches of bootloader in the order they appear.
if len(config.Target.BootPatches) > 0 {
err = applyPatches(result.Executable, config.Target.BootPatches)
}
if config.RP2040BootPatch() { if config.RP2040BootPatch() {
// Patch the second stage bootloader CRC into the .boot2 section // Patch the second stage bootloader CRC into the .boot2 section
err = patchRP2040BootCRC(result.Executable) err = patchRP2040BootCRC(result.Executable)
@@ -946,16 +915,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
} }
// Print code size if requested. // Print code size if requested.
if config.Options.PrintSizes != "" { if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
sizes, err := loadProgramSize(result.Executable, result.PackagePathMap) packagePathMap := make(map[string]string, len(lprogram.Packages))
for _, pkg := range lprogram.Sorted() {
packagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
}
sizes, err := loadProgramSize(result.Executable, packagePathMap)
if err != nil { if err != nil {
return err return err
} }
switch config.Options.PrintSizes { if config.Options.PrintSizes == "short" {
case "short":
fmt.Printf(" code data bss | flash ram\n") fmt.Printf(" code data bss | flash ram\n")
fmt.Printf("%7d %7d %7d | %7d %7d\n", sizes.Code+sizes.ROData, sizes.Data, sizes.BSS, sizes.Flash(), sizes.RAM()) fmt.Printf("%7d %7d %7d | %7d %7d\n", sizes.Code+sizes.ROData, sizes.Data, sizes.BSS, sizes.Flash(), sizes.RAM())
case "full": } else {
if !config.Debug() { if !config.Debug() {
fmt.Println("warning: data incomplete, remove the -no-debug flag for more detail") fmt.Println("warning: data incomplete, remove the -no-debug flag for more detail")
} }
@@ -967,13 +939,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
} }
fmt.Printf("------------------------------- | --------------- | -------\n") fmt.Printf("------------------------------- | --------------- | -------\n")
fmt.Printf("%7d %7d %7d %7d | %7d %7d | total\n", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS, sizes.Code+sizes.ROData+sizes.Data, sizes.Data+sizes.BSS) fmt.Printf("%7d %7d %7d %7d | %7d %7d | total\n", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS, sizes.Code+sizes.ROData+sizes.Data, sizes.Data+sizes.BSS)
case "html":
const filename = "size-report.html"
err := writeSizeReport(sizes, filename, pkgName)
if err != nil {
return err
}
fmt.Println("Wrote size report to", filename)
} }
} }
@@ -1463,23 +1428,6 @@ func printStacks(calculatedStacks []string, stackSizes map[string]functionStackS
} }
} }
func applyPatches(executable string, bootPatches []string) (err error) {
for _, patch := range bootPatches {
switch patch {
case "rp2040":
err = patchRP2040BootCRC(executable)
// case "rp2350":
// err = patchRP2350BootIMAGE_DEF(executable)
default:
err = errors.New("undefined boot patch name")
}
if err != nil {
return fmt.Errorf("apply boot patch %q: %w", patch, err)
}
}
return nil
}
// RP2040 second stage bootloader CRC32 calculation // RP2040 second stage bootloader CRC32 calculation
// //
// Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf // Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
@@ -1491,7 +1439,7 @@ func patchRP2040BootCRC(executable string) error {
} }
if len(bytes) != 256 { if len(bytes) != 256 {
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes, got %d", len(bytes)) return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes")
} }
// From the 'official' RP2040 checksum script: // From the 'official' RP2040 checksum script:
@@ -1530,10 +1478,3 @@ func lock(path string) func() {
return func() { flock.Close() } return func() { flock.Close() }
} }
func b2u8(b bool) uint8 {
if b {
return 1
}
return 0
}
-1
View File
@@ -33,7 +33,6 @@ func TestClangAttributes(t *testing.T) {
"k210", "k210",
"nintendoswitch", "nintendoswitch",
"riscv-qemu", "riscv-qemu",
"tkey",
"wasip1", "wasip1",
"wasip2", "wasip2",
"wasm", "wasm",
+14 -14
View File
@@ -145,7 +145,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
} }
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no); Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.SSE2AVX = Args.hasArg(OPT_msse2avx);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32)) if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64); Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
@@ -235,7 +234,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical =
Args.hasArg(OPT_femit_compact_unwind_non_canonical); Args.hasArg(OPT_femit_compact_unwind_non_canonical);
Opts.Crel = Args.hasArg(OPT_crel);
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file); Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
@@ -289,14 +287,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
assert(MRI && "Unable to create target register info!"); assert(MRI && "Unable to create target register info!");
MCTargetOptions MCOptions; MCTargetOptions MCOptions;
MCOptions.MCRelaxAll = Opts.RelaxAll;
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind; MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical; MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
MCOptions.Crel = Opts.Crel;
MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations;
MCOptions.X86Sse2Avx = Opts.SSE2AVX;
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile; MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
std::unique_ptr<MCAsmInfo> MAI( std::unique_ptr<MCAsmInfo> MAI(
@@ -305,7 +297,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
// Ensure MCAsmInfo initialization occurs before any use, otherwise sections // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
// may be created with a combination of default and explicit settings. // may be created with a combination of default and explicit settings.
MAI->setCompressDebugSections(Opts.CompressDebugSections);
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
if (Opts.OutputPath.empty()) if (Opts.OutputPath.empty())
@@ -349,6 +343,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion); MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
Ctx.setObjectFileInfo(MOFI.get()); Ctx.setObjectFileInfo(MOFI.get());
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly) if (Opts.GenDwarfForAssembly)
Ctx.setGenDwarfForAssembly(true); Ctx.setGenDwarfForAssembly(true);
if (!Opts.DwarfDebugFlags.empty()) if (!Opts.DwarfDebugFlags.empty())
@@ -385,9 +381,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.MCNoWarn = Opts.NoWarn; MCOptions.MCNoWarn = Opts.NoWarn;
MCOptions.MCFatalWarnings = Opts.FatalWarnings; MCOptions.MCFatalWarnings = Opts.FatalWarnings;
MCOptions.MCNoTypeCheck = Opts.NoTypeCheck; MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
MCOptions.ShowMCInst = Opts.ShowInst;
MCOptions.AsmVerbose = true;
MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;
MCOptions.ABIName = Opts.TargetABI; MCOptions.ABIName = Opts.TargetABI;
// FIXME: There is a bit of code duplication with addPassesToEmitFile. // FIXME: There is a bit of code duplication with addPassesToEmitFile.
@@ -402,8 +395,10 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
auto FOut = std::make_unique<formatted_raw_ostream>(*Out); auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), IP, Str.reset(TheTarget->createAsmStreamer(
std::move(CE), std::move(MAB))); Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) { } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx)); Str.reset(createNullStreamer(Ctx));
} else { } else {
@@ -426,7 +421,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Triple T(Opts.Triple); Triple T(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer( Str.reset(TheTarget->createMCObjectStreamer(
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI)); T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->initSections(Opts.NoExecStack, *STI); Str.get()->initSections(Opts.NoExecStack, *STI);
} }
@@ -439,6 +436,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Str.get()->emitZeros(1); Str.get()->emitZeros(1);
} }
// Assembly to object compilation should leverage assembly info.
Str->setUseAssemblerInfoForParsing(true);
bool Failed = false; bool Failed = false;
std::unique_ptr<MCAsmParser> Parser( std::unique_ptr<MCAsmParser> Parser(
+1 -25
View File
@@ -38,17 +38,10 @@ struct AssemblerInvocation {
/// @{ /// @{
std::vector<std::string> IncludePaths; std::vector<std::string> IncludePaths;
LLVM_PREFERRED_TYPE(bool)
unsigned NoInitialTextSection : 1; unsigned NoInitialTextSection : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SaveTemporaryLabels : 1; unsigned SaveTemporaryLabels : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned GenDwarfForAssembly : 1; unsigned GenDwarfForAssembly : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned RelaxELFRelocations : 1; unsigned RelaxELFRelocations : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SSE2AVX : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Dwarf64 : 1; unsigned Dwarf64 : 1;
unsigned DwarfVersion; unsigned DwarfVersion;
std::string DwarfDebugFlags; std::string DwarfDebugFlags;
@@ -73,9 +66,7 @@ struct AssemblerInvocation {
FT_Obj ///< Object file output. FT_Obj ///< Object file output.
}; };
FileType OutputType; FileType OutputType;
LLVM_PREFERRED_TYPE(bool)
unsigned ShowHelp : 1; unsigned ShowHelp : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned ShowVersion : 1; unsigned ShowVersion : 1;
/// @} /// @}
@@ -83,41 +74,28 @@ struct AssemblerInvocation {
/// @{ /// @{
unsigned OutputAsmVariant; unsigned OutputAsmVariant;
LLVM_PREFERRED_TYPE(bool)
unsigned ShowEncoding : 1; unsigned ShowEncoding : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned ShowInst : 1; unsigned ShowInst : 1;
/// @} /// @}
/// @name Assembler Options /// @name Assembler Options
/// @{ /// @{
LLVM_PREFERRED_TYPE(bool)
unsigned RelaxAll : 1; unsigned RelaxAll : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned NoExecStack : 1; unsigned NoExecStack : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned FatalWarnings : 1; unsigned FatalWarnings : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned NoWarn : 1; unsigned NoWarn : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned NoTypeCheck : 1; unsigned NoTypeCheck : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IncrementalLinkerCompatible : 1; unsigned IncrementalLinkerCompatible : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned EmbedBitcode : 1; unsigned EmbedBitcode : 1;
/// Whether to emit DWARF unwind info. /// Whether to emit DWARF unwind info.
EmitDwarfUnwindType EmitDwarfUnwind; EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries. // Whether to emit compact-unwind for non-canonical entries.
// Note: maybe overriden by other constraints. // Note: maybe overridden by other constraints.
LLVM_PREFERRED_TYPE(bool)
unsigned EmitCompactUnwindNonCanonical : 1; unsigned EmitCompactUnwindNonCanonical : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Crel : 1;
/// The name of the relocation model to use. /// The name of the relocation model to use.
std::string RelocationModel; std::string RelocationModel;
@@ -148,7 +126,6 @@ public:
ShowInst = 0; ShowInst = 0;
ShowEncoding = 0; ShowEncoding = 0;
RelaxAll = 0; RelaxAll = 0;
SSE2AVX = 0;
NoExecStack = 0; NoExecStack = 0;
FatalWarnings = 0; FatalWarnings = 0;
NoWarn = 0; NoWarn = 0;
@@ -159,7 +136,6 @@ public:
EmbedBitcode = 0; EmbedBitcode = 0;
EmitDwarfUnwind = EmitDwarfUnwindType::Default; EmitDwarfUnwind = EmitDwarfUnwindType::Default;
EmitCompactUnwindNonCanonical = false; EmitCompactUnwindNonCanonical = false;
Crel = false;
} }
static bool CreateFromArgs(AssemblerInvocation &Res, static bool CreateFromArgs(AssemblerInvocation &Res,
+2 -2
View File
@@ -26,7 +26,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
// Version range supported by TinyGo. // Version range supported by TinyGo.
const minorMin = 19 const minorMin = 19
const minorMax = 24 const minorMax = 23
// Check that we support this Go toolchain version. // Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion() gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
@@ -36,7 +36,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax { if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
// Note: when this gets updated, also update the Go compatibility matrix: // 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 // https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor) return nil, fmt.Errorf("requires go version 1.19 through 1.23, got go%d.%d", gorootMajor, gorootMinor)
} }
// Check that the Go toolchain version isn't too new, if we haven't been // Check that the Go toolchain version isn't too new, if we haven't been
-10
View File
@@ -116,7 +116,6 @@ var libMusl = Library{
"env/*.c", "env/*.c",
"errno/*.c", "errno/*.c",
"exit/*.c", "exit/*.c",
"fcntl/*.c",
"internal/defsysinfo.c", "internal/defsysinfo.c",
"internal/libc.c", "internal/libc.c",
"internal/syscall_ret.c", "internal/syscall_ret.c",
@@ -128,7 +127,6 @@ var libMusl = Library{
"malloc/mallocng/*.c", "malloc/mallocng/*.c",
"mman/*.c", "mman/*.c",
"math/*.c", "math/*.c",
"misc/*.c",
"multibyte/*.c", "multibyte/*.c",
"signal/" + arch + "/*.s", "signal/" + arch + "/*.s",
"signal/*.c", "signal/*.c",
@@ -138,20 +136,12 @@ var libMusl = Library{
"thread/*.c", "thread/*.c",
"time/*.c", "time/*.c",
"unistd/*.c", "unistd/*.c",
"process/*.c",
} }
if arch == "arm" { if arch == "arm" {
// These files need to be added to the start for some reason. // These files need to be added to the start for some reason.
globs = append([]string{"thread/arm/*.c"}, globs...) globs = append([]string{"thread/arm/*.c"}, globs...)
} }
if arch != "aarch64" && arch != "mips" {
//aarch64 and mips have no architecture specific code, either they
// are not supported or don't need any?
globs = append([]string{"process/" + arch + "/*.s"}, globs...)
}
var sources []string var sources []string
seenSources := map[string]struct{}{} seenSources := map[string]struct{}{}
basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/" basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/"
-1
View File
@@ -34,7 +34,6 @@ var libPicolibc = Library{
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU "-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
"-D__OBSOLETE_MATH_DOUBLE=0", "-D__OBSOLETE_MATH_DOUBLE=0",
"-D_WANT_IO_C99_FORMATS", "-D_WANT_IO_C99_FORMATS",
"-D__PICOLIBC_ERRNO_FUNCTION=__errno_location",
"-nostdlibinc", "-nostdlibinc",
"-isystem", newlibDir + "/libc/include", "-isystem", newlibDir + "/libc/include",
"-I" + newlibDir + "/libc/tinystdio", "-I" + newlibDir + "/libc/tinystdio",
-56
View File
@@ -1,56 +0,0 @@
package builder
import (
_ "embed"
"fmt"
"html/template"
"os"
)
//go:embed size-report.html
var sizeReportBase string
func writeSizeReport(sizes *programSize, filename, pkgName string) error {
tmpl, err := template.New("report").Parse(sizeReportBase)
if err != nil {
return err
}
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("could not open report file: %w", err)
}
defer f.Close()
// Prepare data for the report.
type sizeLine struct {
Name string
Size *packageSize
}
programData := []sizeLine{}
for _, name := range sizes.sortedPackageNames() {
pkgSize := sizes.Packages[name]
programData = append(programData, sizeLine{
Name: name,
Size: pkgSize,
})
}
sizeTotal := map[string]uint64{
"code": sizes.Code,
"rodata": sizes.ROData,
"data": sizes.Data,
"bss": sizes.BSS,
"flash": sizes.Flash(),
}
// Write the report.
err = tmpl.Execute(f, map[string]any{
"pkgName": pkgName,
"sizes": programData,
"sizeTotal": sizeTotal,
})
if err != nil {
return fmt.Errorf("could not create report file: %w", err)
}
return nil
}
-109
View File
@@ -1,109 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Size Report for {{.pkgName}}</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
.table-vertical-border {
border-left: calc(var(--bs-border-width) * 2) solid currentcolor;
}
/* Hover on only the rows that are clickable. */
.row-package:hover > * {
--bs-table-color-state: var(--bs-table-hover-color);
--bs-table-bg-state: var(--bs-table-hover-bg);
}
</style>
</head>
<body>
<div class="container-xxl">
<h1>Size Report for {{.pkgName}}</h1>
<p>How much space is used by Go packages, C libraries, and other bits to set up the program environment.</p>
<ul>
<li><strong>Code</strong> is the actual program code (machine code instructions).</li>
<li><strong>Read-only data</strong> are read-only global variables. On most microcontrollers, these are stored in flash and do not take up any RAM.</li>
<li><strong>Data</strong> are writable global variables with a non-zero initializer. On microcontrollers, they are copied from flash to RAM on reset.</li>
<li><strong>BSS</strong> are writable global variables that are zero initialized. They do not take up any space in the binary, but do take up RAM. On microcontrollers, this area is zeroed on reset.</li>
</ul>
<p>The binary size consists of code, read-only data, and data. On microcontrollers, this is exactly the size of the firmware image. On other systems, there is some extra overhead: binary metadata (headers of the ELF/MachO/COFF file), debug information, exception tables, symbol names, etc. Using <code>-no-debug</code> strips most of those.</p>
<h2>Program breakdown</h2>
<p>You can click on the rows below to see which files contribute to the binary size.</p>
<div class="table-responsive">
<table class="table w-auto">
<thead>
<tr>
<th>Package</th>
<th class="table-vertical-border">Code</th>
<th>Read-only data</th>
<th>Data</th>
<th title="zero-initialized data">BSS</th>
<th class="table-vertical-border" style="min-width: 16em">Binary size</th>
</tr>
</thead>
<tbody class="table-group-divider">
{{range $i, $pkg := .sizes}}
<tr class="row-package" data-collapse=".collapse-row-{{$i}}">
<td>{{.Name}}</td>
<td class="table-vertical-border">{{.Size.Code}}</td>
<td>{{.Size.ROData}}</td>
<td>{{.Size.Data}}</td>
<td>{{.Size.BSS}}</td>
<td class="table-vertical-border" style="background: linear-gradient(to right, var(--bs-info-bg-subtle) {{.Size.FlashPercent}}%, var(--bs-table-bg) {{.Size.FlashPercent}}%)">
{{.Size.Flash}}
</td>
</tr>
{{range $filename, $sizes := .Size.Sub}}
<tr class="table-secondary collapse collapse-row-{{$i}}">
<td class="ps-4">
{{if eq $filename ""}}
(unknown file)
{{else}}
{{$filename}}
{{end}}
</td>
<td class="table-vertical-border">{{$sizes.Code}}</td>
<td>{{$sizes.ROData}}</td>
<td>{{$sizes.Data}}</td>
<td>{{$sizes.BSS}}</td>
<td class="table-vertical-border" style="background: linear-gradient(to right, var(--bs-info-bg-subtle) {{$sizes.FlashPercent}}%, var(--bs-table-bg) {{$sizes.FlashPercent}}%)">
{{$sizes.Flash}}
</td>
</tr>
{{end}}
{{end}}
</tbody>
<tfoot class="table-group-divider">
<tr>
<th>Total</th>
<td class="table-vertical-border">{{.sizeTotal.code}}</td>
<td>{{.sizeTotal.rodata}}</td>
<td>{{.sizeTotal.data}}</td>
<td>{{.sizeTotal.bss}}</td>
<td class="table-vertical-border">{{.sizeTotal.flash}}</td>
</tr>
</tfoot>
</table>
</div>
</div>
<script>
// Make table rows toggleable to show filenames.
for (let clickable of document.querySelectorAll('.row-package')) {
clickable.addEventListener('click', e => {
for (let row of document.querySelectorAll(clickable.dataset.collapse)) {
row.classList.toggle('show');
}
});
}
</script>
</body>
</html>
+47 -102
View File
@@ -12,7 +12,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"sort" "sort"
"strings" "strings"
@@ -25,7 +24,7 @@ const sizesDebug = false
// programSize contains size statistics per package of a compiled program. // programSize contains size statistics per package of a compiled program.
type programSize struct { type programSize struct {
Packages map[string]*packageSize Packages map[string]packageSize
Code uint64 Code uint64
ROData uint64 ROData uint64
Data uint64 Data uint64
@@ -53,29 +52,13 @@ func (ps *programSize) RAM() uint64 {
return ps.Data + ps.BSS return ps.Data + ps.BSS
} }
// Return the package size information for a given package path, creating it if
// it doesn't exist yet.
func (ps *programSize) getPackage(path string) *packageSize {
if field, ok := ps.Packages[path]; ok {
return field
}
field := &packageSize{
Program: ps,
Sub: map[string]*packageSize{},
}
ps.Packages[path] = field
return field
}
// packageSize contains the size of a package, calculated from the linked object // packageSize contains the size of a package, calculated from the linked object
// file. // file.
type packageSize struct { type packageSize struct {
Program *programSize Code uint64
Code uint64 ROData uint64
ROData uint64 Data uint64
Data uint64 BSS uint64
BSS uint64
Sub map[string]*packageSize
} }
// Flash usage in regular microcontrollers. // Flash usage in regular microcontrollers.
@@ -88,31 +71,6 @@ func (ps *packageSize) RAM() uint64 {
return ps.Data + ps.BSS return ps.Data + ps.BSS
} }
// Flash usage in regular microcontrollers, as a percentage of the total flash
// usage of the program.
func (ps *packageSize) FlashPercent() float64 {
return float64(ps.Flash()) / float64(ps.Program.Flash()) * 100
}
// Add a single size data point to this package.
// This must only be called while calculating package size, not afterwards.
func (ps *packageSize) addSize(getField func(*packageSize, bool) *uint64, filename string, size uint64, isVariable bool) {
if size == 0 {
return
}
// Add size for the package.
*getField(ps, isVariable) += size
// Add size for file inside package.
sub, ok := ps.Sub[filename]
if !ok {
sub = &packageSize{Program: ps.Program}
ps.Sub[filename] = sub
}
*getField(sub, isVariable) += size
}
// A mapping of a single chunk of code or data to a file path. // A mapping of a single chunk of code or data to a file path.
type addressLine struct { type addressLine struct {
Address uint64 Address uint64
@@ -236,22 +194,11 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64
if !prevLineEntry.EndSequence { if !prevLineEntry.EndSequence {
// The chunk describes the code from prevLineEntry to // The chunk describes the code from prevLineEntry to
// lineEntry. // lineEntry.
path := prevLineEntry.File.Name
if runtime.GOOS == "windows" {
// Work around a Clang bug on Windows:
// https://github.com/llvm/llvm-project/issues/117317
path = strings.ReplaceAll(path, "\\\\", "\\")
// wasi-libc likes to use forward slashes, but we
// canonicalize everything to use backwards slashes as
// is common on Windows.
path = strings.ReplaceAll(path, "/", "\\")
}
line := addressLine{ line := addressLine{
Address: prevLineEntry.Address + codeOffset, Address: prevLineEntry.Address + codeOffset,
Length: lineEntry.Address - prevLineEntry.Address, Length: lineEntry.Address - prevLineEntry.Address,
Align: codeAlignment, Align: codeAlignment,
File: path, File: prevLineEntry.File.Name,
} }
if line.Length != 0 { if line.Length != 0 {
addresses = append(addresses, line) addresses = append(addresses, line)
@@ -826,40 +773,49 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Now finally determine the binary/RAM size usage per package by going // Now finally determine the binary/RAM size usage per package by going
// through each allocated section. // through each allocated section.
sizes := make(map[string]*packageSize) sizes := make(map[string]packageSize)
program := &programSize{
Packages: sizes,
}
for _, section := range sections { for _, section := range sections {
switch section.Type { switch section.Type {
case memoryCode: case memoryCode:
readSection(section, addresses, program, func(ps *packageSize, isVariable bool) *uint64 { readSection(section, addresses, func(path string, size uint64, isVariable bool) {
field := sizes[path]
if isVariable { if isVariable {
return &ps.ROData field.ROData += size
} else {
field.Code += size
} }
return &ps.Code sizes[path] = field
}, packagePathMap) }, packagePathMap)
case memoryROData: case memoryROData:
readSection(section, addresses, program, func(ps *packageSize, isVariable bool) *uint64 { readSection(section, addresses, func(path string, size uint64, isVariable bool) {
return &ps.ROData field := sizes[path]
field.ROData += size
sizes[path] = field
}, packagePathMap) }, packagePathMap)
case memoryData: case memoryData:
readSection(section, addresses, program, func(ps *packageSize, isVariable bool) *uint64 { readSection(section, addresses, func(path string, size uint64, isVariable bool) {
return &ps.Data field := sizes[path]
field.Data += size
sizes[path] = field
}, packagePathMap) }, packagePathMap)
case memoryBSS: case memoryBSS:
readSection(section, addresses, program, func(ps *packageSize, isVariable bool) *uint64 { readSection(section, addresses, func(path string, size uint64, isVariable bool) {
return &ps.BSS field := sizes[path]
field.BSS += size
sizes[path] = field
}, packagePathMap) }, packagePathMap)
case memoryStack: case memoryStack:
// We store the C stack as a pseudo-package. // We store the C stack as a pseudo-package.
program.getPackage("C stack").addSize(func(ps *packageSize, isVariable bool) *uint64 { sizes["C stack"] = packageSize{
return &ps.BSS BSS: section.Size,
}, "", section.Size, false) }
} }
} }
// ...and summarize the results. // ...and summarize the results.
program := &programSize{
Packages: sizes,
}
for _, pkg := range sizes { for _, pkg := range sizes {
program.Code += pkg.Code program.Code += pkg.Code
program.ROData += pkg.ROData program.ROData += pkg.ROData
@@ -870,8 +826,8 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
} }
// readSection determines for each byte in this section to which package it // readSection determines for each byte in this section to which package it
// belongs. // belongs. It reports this usage through the addSize callback.
func readSection(section memorySection, addresses []addressLine, program *programSize, getField func(*packageSize, bool) *uint64, packagePathMap map[string]string) { func readSection(section memorySection, addresses []addressLine, addSize func(string, uint64, bool), packagePathMap map[string]string) {
// The addr variable tracks at which address we are while going through this // The addr variable tracks at which address we are while going through this
// section. We start at the beginning. // section. We start at the beginning.
addr := section.Address addr := section.Address
@@ -893,9 +849,9 @@ func readSection(section memorySection, addresses []addressLine, program *progra
addrAligned := (addr + line.Align - 1) &^ (line.Align - 1) addrAligned := (addr + line.Align - 1) &^ (line.Align - 1)
if line.Align > 1 && addrAligned >= line.Address { if line.Align > 1 && addrAligned >= line.Address {
// It is, assume that's what causes the gap. // It is, assume that's what causes the gap.
program.getPackage("(padding)").addSize(getField, "", line.Address-addr, true) addSize("(padding)", line.Address-addr, true)
} else { } else {
program.getPackage("(unknown)").addSize(getField, "", line.Address-addr, false) addSize("(unknown)", line.Address-addr, false)
if sizesDebug { if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (gap), alignment=%d\n", addr, line.Address, line.Address-addr, line.Align) fmt.Printf("%08x..%08x %5d: unknown (gap), alignment=%d\n", addr, line.Address, line.Address-addr, line.Align)
} }
@@ -917,8 +873,7 @@ func readSection(section memorySection, addresses []addressLine, program *progra
length = line.Length - (addr - line.Address) length = line.Length - (addr - line.Address)
} }
// Finally, mark this chunk of memory as used by the given package. // Finally, mark this chunk of memory as used by the given package.
packagePath, filename := findPackagePath(line.File, packagePathMap) addSize(findPackagePath(line.File, packagePathMap), length, line.IsVariable)
program.getPackage(packagePath).addSize(getField, filename, length, line.IsVariable)
addr = line.Address + line.Length addr = line.Address + line.Length
} }
if addr < sectionEnd { if addr < sectionEnd {
@@ -927,9 +882,9 @@ func readSection(section memorySection, addresses []addressLine, program *progra
if section.Align > 1 && addrAligned >= sectionEnd { if section.Align > 1 && addrAligned >= sectionEnd {
// The gap is caused by the section alignment. // The gap is caused by the section alignment.
// For example, if a .rodata section ends with a non-aligned string. // For example, if a .rodata section ends with a non-aligned string.
program.getPackage("(padding)").addSize(getField, "", sectionEnd-addr, true) addSize("(padding)", sectionEnd-addr, true)
} else { } else {
program.getPackage("(unknown)").addSize(getField, "", sectionEnd-addr, false) addSize("(unknown)", sectionEnd-addr, false)
if sizesDebug { if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (end), alignment=%d\n", addr, sectionEnd, sectionEnd-addr, section.Align) fmt.Printf("%08x..%08x %5d: unknown (end), alignment=%d\n", addr, sectionEnd, sectionEnd-addr, section.Align)
} }
@@ -939,25 +894,17 @@ func readSection(section memorySection, addresses []addressLine, program *progra
// findPackagePath returns the Go package (or a pseudo package) for the given // findPackagePath returns the Go package (or a pseudo package) for the given
// path. It uses some heuristics, for example for some C libraries. // path. It uses some heuristics, for example for some C libraries.
func findPackagePath(path string, packagePathMap map[string]string) (packagePath, filename string) { func findPackagePath(path string, packagePathMap map[string]string) string {
// Check whether this path is part of one of the compiled packages. // Check whether this path is part of one of the compiled packages.
packagePath, ok := packagePathMap[filepath.Dir(path)] packagePath, ok := packagePathMap[filepath.Dir(path)]
if ok { if !ok {
// Directory is known as a Go package.
// Add the file itself as well.
filename = filepath.Base(path)
} else {
if strings.HasPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")) { if strings.HasPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")) {
// Emit C libraries (in the lib subdirectory of TinyGo) as a single // Emit C libraries (in the lib subdirectory of TinyGo) as a single
// package, with a "C" prefix. For example: "C picolibc" for the // package, with a "C" prefix. For example: "C compiler-rt" for the
// baremetal libc. // compiler runtime library from LLVM.
libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator)) packagePath = "C " + strings.Split(strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")), string(os.PathSeparator))[1]
parts := strings.SplitN(libPath, string(os.PathSeparator), 2) } else if strings.HasPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project")) {
packagePath = "C " + parts[0]
filename = parts[1]
} else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) {
packagePath = "C compiler-rt" packagePath = "C compiler-rt"
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
} else if packageSymbolRegexp.MatchString(path) { } else if packageSymbolRegexp.MatchString(path) {
// Parse symbol names like main$alloc or runtime$string. // Parse symbol names like main$alloc or runtime$string.
packagePath = path[:strings.LastIndex(path, "$")] packagePath = path[:strings.LastIndex(path, "$")]
@@ -980,11 +927,9 @@ func findPackagePath(path string, packagePathMap map[string]string) (packagePath
// fixed in the compiler. // fixed in the compiler.
packagePath = "-" packagePath = "-"
} else { } else {
// This is some other path. Not sure what it is, so just emit its // This is some other path. Not sure what it is, so just emit its directory.
// directory as a fallback. packagePath = filepath.Dir(path) // fallback
packagePath = filepath.Dir(path)
filename = filepath.Base(path)
} }
} }
return return packagePath
} }
+23 -71
View File
@@ -1,7 +1,6 @@
package builder package builder
import ( import (
"regexp"
"runtime" "runtime"
"testing" "testing"
"time" "time"
@@ -42,9 +41,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test. // This is a small number of very diverse targets that we want to test.
tests := []sizeTest{ tests := []sizeTest{
// microcontrollers // microcontrollers
{"hifive1b", "examples/echo", 4560, 280, 0, 2268}, {"hifive1b", "examples/echo", 4568, 280, 0, 2268},
{"microbit", "examples/serial", 2916, 388, 8, 2272}, {"microbit", "examples/serial", 2868, 388, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7359, 1489, 116, 6912}, {"wioterminal", "examples/pininterrupt", 6104, 1484, 116, 6832},
// TODO: also check wasm. Right now this is difficult, because // TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the // wasm binaries are run through wasm-opt and therefore the
@@ -56,7 +55,26 @@ func TestBinarySize(t *testing.T) {
t.Parallel() t.Parallel()
// Build the binary. // Build the binary.
result := buildBinary(t, tc.target, tc.path) options := compileopts.Options{
Target: tc.target,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(tc.path, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
// Check whether the size of the binary matches the expected size. // Check whether the size of the binary matches the expected size.
sizes, err := loadProgramSize(result.Executable, nil) sizes, err := loadProgramSize(result.Executable, nil)
@@ -72,69 +90,3 @@ func TestBinarySize(t *testing.T) {
}) })
} }
} }
// Check that the -size=full flag attributes binary size to the correct package
// without filesystem paths and things like that.
func TestSizeFull(t *testing.T) {
tests := []string{
"microbit",
"wasip1",
}
libMatch := regexp.MustCompile(`^C [a-z -]+$`) // example: "C interrupt vector"
pkgMatch := regexp.MustCompile(`^[a-z/]+$`) // example: "internal/task"
for _, target := range tests {
target := target
t.Run(target, func(t *testing.T) {
t.Parallel()
// Build the binary.
result := buildBinary(t, target, "examples/serial")
// Check whether the binary doesn't contain any unexpected package
// names.
sizes, err := loadProgramSize(result.Executable, result.PackagePathMap)
if err != nil {
t.Fatal("could not read program size:", err)
}
for _, pkg := range sizes.sortedPackageNames() {
if pkg == "(padding)" || pkg == "(unknown)" {
// TODO: correctly attribute all unknown binary size.
continue
}
if libMatch.MatchString(pkg) {
continue
}
if pkgMatch.MatchString(pkg) {
continue
}
t.Error("unexpected package name in size output:", pkg)
}
})
}
}
func buildBinary(t *testing.T, targetString, pkgName string) BuildResult {
options := compileopts.Options{
Target: targetString,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(pkgName, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
return result
}
+7 -23
View File
@@ -32,26 +32,10 @@ func runCCompiler(flags ...string) error {
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
// Make sure the command doesn't use any environmental variables. // Make sure the command doesn't use any environmental variables.
// Most importantly, it should not use C_INCLUDE_PATH and the like. // Most importantly, it should not use C_INCLUDE_PATH and the like. But
// removing all environmental variables also works.
cmd.Env = []string{} cmd.Env = []string{}
// Let some environment variables through. One important one is the
// temporary directory, especially on Windows it looks like Clang breaks if
// the temporary directory has not been set.
// See: https://github.com/tinygo-org/tinygo/issues/4557
// Also see: https://github.com/llvm/llvm-project/blob/release/18.x/llvm/lib/Support/Unix/Path.inc#L1435
for _, env := range os.Environ() {
// We could parse the key and look it up in a map, but since there are
// only a few keys iterating through them is easier and maybe even
// faster.
for _, prefix := range []string{"TMPDIR=", "TMP=", "TEMP=", "TEMPDIR="} {
if strings.HasPrefix(env, prefix) {
cmd.Env = append(cmd.Env, env)
break
}
}
}
return cmd.Run() return cmd.Run()
} }
@@ -114,8 +98,8 @@ func parseLLDErrors(text string) error {
// Check for undefined symbols. // Check for undefined symbols.
// This can happen in some cases like with CGo and //go:linkname tricker. // This can happen in some cases like with CGo and //go:linkname tricker.
if matches := regexp.MustCompile(`^ld.lld(-[0-9]+)?: error: undefined symbol: (.*)\n`).FindStringSubmatch(message); matches != nil { if matches := regexp.MustCompile(`^ld.lld: error: undefined symbol: (.*)\n`).FindStringSubmatch(message); matches != nil {
symbolName := matches[2] symbolName := matches[1]
for _, line := range strings.Split(message, "\n") { for _, line := range strings.Split(message, "\n") {
matches := regexp.MustCompile(`referenced by .* \(((.*):([0-9]+))\)`).FindStringSubmatch(line) matches := regexp.MustCompile(`referenced by .* \(((.*):([0-9]+))\)`).FindStringSubmatch(line)
if matches != nil { if matches != nil {
@@ -134,9 +118,9 @@ func parseLLDErrors(text string) error {
} }
// Check for flash/RAM overflow. // Check for flash/RAM overflow.
if matches := regexp.MustCompile(`^ld.lld(-[0-9]+)?: error: section '(.*?)' will not fit in region '(.*?)': overflowed by ([0-9]+) bytes$`).FindStringSubmatch(message); matches != nil { if matches := regexp.MustCompile(`^ld.lld: error: section '(.*?)' will not fit in region '(.*?)': overflowed by ([0-9]+) bytes$`).FindStringSubmatch(message); matches != nil {
region := matches[3] region := matches[2]
n, err := strconv.ParseUint(matches[4], 10, 64) n, err := strconv.ParseUint(matches[3], 10, 64)
if err != nil { if err != nil {
// Should not happen at all (unless it overflows an uint64 for some reason). // Should not happen at all (unless it overflows an uint64 for some reason).
continue continue
+59 -206
View File
@@ -18,7 +18,6 @@ import (
"go/scanner" "go/scanner"
"go/token" "go/token"
"path/filepath" "path/filepath"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -43,7 +42,6 @@ type cgoPackage struct {
fset *token.FileSet fset *token.FileSet
tokenFiles map[string]*token.File tokenFiles map[string]*token.File
definedGlobally map[string]ast.Node definedGlobally map[string]ast.Node
noescapingFuncs map[string]*noescapingFunc // #cgo noescape lines
anonDecls map[interface{}]string anonDecls map[interface{}]string
cflags []string // CFlags from #cgo lines cflags []string // CFlags from #cgo lines
ldflags []string // LDFlags from #cgo lines ldflags []string // LDFlags from #cgo lines
@@ -82,28 +80,21 @@ type bitfieldInfo struct {
endBit int64 // may be 0 meaning "until the end of the field" endBit int64 // may be 0 meaning "until the end of the field"
} }
// Information about a #cgo noescape line in the source code.
type noescapingFunc struct {
name string
pos token.Pos
used bool // true if used somewhere in the source (for proper error reporting)
}
// cgoAliases list type aliases between Go and C, for types that are equivalent // cgoAliases list type aliases between Go and C, for types that are equivalent
// in both languages. See addTypeAliases. // in both languages. See addTypeAliases.
var cgoAliases = map[string]string{ var cgoAliases = map[string]string{
"_Cgo_int8_t": "int8", "C.int8_t": "int8",
"_Cgo_int16_t": "int16", "C.int16_t": "int16",
"_Cgo_int32_t": "int32", "C.int32_t": "int32",
"_Cgo_int64_t": "int64", "C.int64_t": "int64",
"_Cgo_uint8_t": "uint8", "C.uint8_t": "uint8",
"_Cgo_uint16_t": "uint16", "C.uint16_t": "uint16",
"_Cgo_uint32_t": "uint32", "C.uint32_t": "uint32",
"_Cgo_uint64_t": "uint64", "C.uint64_t": "uint64",
"_Cgo_uintptr_t": "uintptr", "C.uintptr_t": "uintptr",
"_Cgo_float": "float32", "C.float": "float32",
"_Cgo_double": "float64", "C.double": "float64",
"_Cgo__Bool": "bool", "C._Bool": "bool",
} }
// builtinAliases are handled specially because they only exist on the Go side // builtinAliases are handled specially because they only exist on the Go side
@@ -145,105 +136,38 @@ typedef unsigned long long _Cgo_ulonglong;
// The string/bytes functions below implement C.CString etc. To make sure the // The string/bytes functions below implement C.CString etc. To make sure the
// runtime doesn't need to know the C int type, lengths are converted to uintptr // runtime doesn't need to know the C int type, lengths are converted to uintptr
// first. // first.
const generatedGoFilePrefixBase = ` // These functions will be modified to get a "C." prefix, so the source below
import "syscall" // doesn't reflect the final AST.
const generatedGoFilePrefix = `
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func __GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func __GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func __CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
`
const generatedGoFilePrefixOther = generatedGoFilePrefixBase + `
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
}
`
// Windows uses fake errno values in the syscall package.
// See for example: https://github.com/golang/go/issues/23468
// TinyGo uses mingw-w64 though, which does have defined errno values. Since the
// syscall package is the standard library one we can't change it, but we can
// map the errno values to match the values in the syscall package.
// Source of the errno values: lib/mingw-w64/mingw-w64-headers/crt/errno.h
const generatedGoFilePrefixWindows = generatedGoFilePrefixBase + `
var _Cgo___errno_mapping = [...]syscall.Errno{
1: syscall.EPERM,
2: syscall.ENOENT,
3: syscall.ESRCH,
4: syscall.EINTR,
5: syscall.EIO,
6: syscall.ENXIO,
7: syscall.E2BIG,
8: syscall.ENOEXEC,
9: syscall.EBADF,
10: syscall.ECHILD,
11: syscall.EAGAIN,
12: syscall.ENOMEM,
13: syscall.EACCES,
14: syscall.EFAULT,
16: syscall.EBUSY,
17: syscall.EEXIST,
18: syscall.EXDEV,
19: syscall.ENODEV,
20: syscall.ENOTDIR,
21: syscall.EISDIR,
22: syscall.EINVAL,
23: syscall.ENFILE,
24: syscall.EMFILE,
25: syscall.ENOTTY,
27: syscall.EFBIG,
28: syscall.ENOSPC,
29: syscall.ESPIPE,
30: syscall.EROFS,
31: syscall.EMLINK,
32: syscall.EPIPE,
33: syscall.EDOM,
34: syscall.ERANGE,
36: syscall.EDEADLK,
38: syscall.ENAMETOOLONG,
39: syscall.ENOLCK,
40: syscall.ENOSYS,
41: syscall.ENOTEMPTY,
42: syscall.EILSEQ,
}
func _Cgo___get_errno() error {
num := _Cgo___get_errno_num()
if num < uintptr(len(_Cgo___errno_mapping)) {
if mapped := _Cgo___errno_mapping[num]; mapped != 0 {
return mapped
}
}
return syscall.Errno(num)
} }
` `
@@ -254,7 +178,7 @@ func _Cgo___get_errno() error {
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file // functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
// hashes of the accessed C header files. If there is one or more error, it // hashes of the accessed C header files. If there is one or more error, it
// returns these in the []error slice but still modifies the AST. // returns these in the []error slice but still modifies the AST.
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, goos 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{ p := &cgoPackage{
packageName: files[0].Name.Name, packageName: files[0].Name.Name,
currentDir: dir, currentDir: dir,
@@ -262,7 +186,6 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
fset: fset, fset: fset,
tokenFiles: map[string]*token.File{}, tokenFiles: map[string]*token.File{},
definedGlobally: map[string]ast.Node{}, definedGlobally: map[string]ast.Node{},
noescapingFuncs: map[string]*noescapingFunc{},
anonDecls: map[interface{}]string{}, anonDecls: map[interface{}]string{},
visitedFiles: map[string][]byte{}, visitedFiles: map[string][]byte{},
} }
@@ -287,12 +210,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
// Construct a new in-memory AST for CGo declarations of this package. // Construct a new in-memory AST for CGo declarations of this package.
// The first part is written as Go code that is then parsed, but more code // The first part is written as Go code that is then parsed, but more code
// is added later to the AST to declare functions, globals, etc. // is added later to the AST to declare functions, globals, etc.
goCode := "package " + files[0].Name.Name + "\n\n" goCode := "package " + files[0].Name.Name + "\n\n" + generatedGoFilePrefix
if goos == "windows" {
goCode += generatedGoFilePrefixWindows
} else {
goCode += generatedGoFilePrefixOther
}
p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments) p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments)
if err != nil { if err != nil {
// This is always a bug in the cgo package. // This is always a bug in the cgo package.
@@ -302,6 +220,23 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
// If the Comments field is not set to nil, the go/format package will get // If the Comments field is not set to nil, the go/format package will get
// confused about where comments should go. // confused about where comments should go.
p.generated.Comments = nil p.generated.Comments = nil
// Adjust some of the functions in there.
for _, decl := range p.generated.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
switch decl.Name.Name {
case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes", "CBytes", "__CBytes":
// Adjust the name to have a "C." prefix so it is correctly
// resolved.
decl.Name.Name = "C." + decl.Name.Name
}
}
}
// Patch some types, for example *C.char in C.CString.
cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
return cf.walker(cursor, nil)
}, nil)
// Find `import "C"` C fragments in the file. // Find `import "C"` C fragments in the file.
p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
@@ -380,7 +315,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
Tok: token.TYPE, Tok: token.TYPE,
} }
for _, name := range builtinAliases { for _, name := range builtinAliases {
typeSpec := p.getIntegerType("_Cgo_"+name, names["_Cgo_"+name]) typeSpec := p.getIntegerType("C."+name, names["_Cgo_"+name])
gen.Specs = append(gen.Specs, typeSpec) gen.Specs = append(gen.Specs, typeSpec)
} }
p.generated.Decls = append(p.generated.Decls, gen) p.generated.Decls = append(p.generated.Decls, gen)
@@ -409,22 +344,6 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
}) })
} }
// Show an error when a #cgo noescape line isn't used in practice.
// This matches upstream Go. I think the goal is to avoid issues with
// misspelled function names, which seems very useful.
var unusedNoescapeLines []*noescapingFunc
for _, value := range p.noescapingFuncs {
if !value.used {
unusedNoescapeLines = append(unusedNoescapeLines, value)
}
}
sort.SliceStable(unusedNoescapeLines, func(i, j int) bool {
return unusedNoescapeLines[i].pos < unusedNoescapeLines[j].pos
})
for _, value := range unusedNoescapeLines {
p.addError(value.pos, fmt.Sprintf("function %#v in #cgo noescape line is not used", value.name))
}
// Print the newly generated in-memory AST, for debugging. // Print the newly generated in-memory AST, for debugging.
//ast.Print(fset, p.generated) //ast.Print(fset, p.generated)
@@ -490,33 +409,6 @@ func (p *cgoPackage) parseCGoPreprocessorLines(text string, pos token.Pos) strin
} }
text = text[:lineStart] + string(spaces) + text[lineEnd:] text = text[:lineStart] + string(spaces) + text[lineEnd:]
allFields := strings.Fields(line[4:])
switch allFields[0] {
case "noescape":
// The code indicates that pointer parameters will not be captured
// by the called C function.
if len(allFields) < 2 {
p.addErrorAfter(pos, text[:lineStart], "missing function name in #cgo noescape line")
continue
}
if len(allFields) > 2 {
p.addErrorAfter(pos, text[:lineStart], "multiple function names in #cgo noescape line")
continue
}
name := allFields[1]
p.noescapingFuncs[name] = &noescapingFunc{
name: name,
pos: pos,
used: false,
}
continue
case "nocallback":
// We don't do anything special when calling a C function, so there
// appears to be no optimization that we can do here.
// Accept, but ignore the parameter for compatibility.
continue
}
// Get the text before the colon in the #cgo directive. // Get the text before the colon in the #cgo directive.
colon := strings.IndexByte(line, ':') colon := strings.IndexByte(line, ':')
if colon < 0 { if colon < 0 {
@@ -1253,22 +1145,22 @@ func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string { func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string {
// Some types are defined in stdint.h and map directly to a particular Go // Some types are defined in stdint.h and map directly to a particular Go
// type. // type.
if alias := cgoAliases["_Cgo_"+name]; alias != "" { if alias := cgoAliases["C."+name]; alias != "" {
return alias return alias
} }
node := f.getASTDeclNode(name, found) node := f.getASTDeclNode(name, found, iscall)
if node, ok := node.(*ast.FuncDecl); ok { if node, ok := node.(*ast.FuncDecl); ok {
if !iscall { if !iscall {
return node.Name.Name + "$funcaddr" return node.Name.Name + "$funcaddr"
} }
return node.Name.Name return node.Name.Name
} }
return "_Cgo_" + name return "C." + name
} }
// getASTDeclNode will declare the given C AST node (if not already defined) and // getASTDeclNode will declare the given C AST node (if not already defined) and
// returns it. // returns it.
func (f *cgoFile) getASTDeclNode(name string, found clangCursor) ast.Node { func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) ast.Node {
if node, ok := f.defined[name]; ok { if node, ok := f.defined[name]; ok {
// Declaration was found in the current file, so return it immediately. // Declaration was found in the current file, so return it immediately.
return node return node
@@ -1363,8 +1255,8 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
case *elaboratedTypeInfo: case *elaboratedTypeInfo:
// Add struct bitfields. // Add struct bitfields.
for _, bitfield := range elaboratedType.bitfields { for _, bitfield := range elaboratedType.bitfields {
f.createBitfieldGetter(bitfield, "_Cgo_"+name) f.createBitfieldGetter(bitfield, "C."+name)
f.createBitfieldSetter(bitfield, "_Cgo_"+name) f.createBitfieldSetter(bitfield, "C."+name)
} }
if elaboratedType.unionSize != 0 { if elaboratedType.unionSize != 0 {
// Create union getters/setters. // Create union getters/setters.
@@ -1373,7 +1265,7 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
f.addError(elaboratedType.pos, fmt.Sprintf("union must have field with a single name, it has %d names", len(field.Names))) f.addError(elaboratedType.pos, fmt.Sprintf("union must have field with a single name, it has %d names", len(field.Names)))
continue continue
} }
f.createUnionAccessor(field, "_Cgo_"+name) f.createUnionAccessor(field, "C."+name)
} }
} }
} }
@@ -1387,45 +1279,6 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
// separate namespace (no _Cgo_ hacks like in gc). // separate namespace (no _Cgo_ hacks like in gc).
func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) bool { func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) bool {
switch node := cursor.Node().(type) { switch node := cursor.Node().(type) {
case *ast.AssignStmt:
// An assign statement could be something like this:
//
// val, errno := C.some_func()
//
// Check whether it looks like that, and if so, read the errno value and
// return it as the second return value. The call will be transformed
// into something like this:
//
// val, errno := C.some_func(), C.__get_errno()
if len(node.Lhs) != 2 || len(node.Rhs) != 1 {
return true
}
rhs, ok := node.Rhs[0].(*ast.CallExpr)
if !ok {
return true
}
fun, ok := rhs.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
x, ok := fun.X.(*ast.Ident)
if !ok {
return true
}
if found, ok := names[fun.Sel.Name]; ok && x.Name == "C" {
// Replace "C"."some_func" into "C.somefunc".
rhs.Fun = &ast.Ident{
NamePos: x.NamePos,
Name: f.getASTDeclName(fun.Sel.Name, found, true),
}
// Add the errno value as the second value in the statement.
node.Rhs = append(node.Rhs, &ast.CallExpr{
Fun: &ast.Ident{
NamePos: node.Lhs[1].End(),
Name: "_Cgo___get_errno",
},
})
}
case *ast.CallExpr: case *ast.CallExpr:
fun, ok := node.Fun.(*ast.SelectorExpr) fun, ok := node.Fun.(*ast.SelectorExpr)
if !ok { if !ok {
@@ -1447,7 +1300,7 @@ func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) b
return true return true
} }
if x.Name == "C" { if x.Name == "C" {
name := "_Cgo_" + node.Sel.Name name := "C." + node.Sel.Name
if found, ok := names[node.Sel.Name]; ok { if found, ok := names[node.Sel.Name]; ok {
name = f.getASTDeclName(node.Sel.Name, found, false) name = f.getASTDeclName(node.Sel.Name, found, false)
} }
+4 -23
View File
@@ -56,7 +56,7 @@ func TestCGo(t *testing.T) {
} }
// Process the AST with CGo. // Process the AST with CGo.
cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags, "linux") cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
// Check the AST for type errors. // Check the AST for type errors.
var typecheckErrors []error var typecheckErrors []error
@@ -64,7 +64,7 @@ func TestCGo(t *testing.T) {
Error: func(err error) { Error: func(err error) {
typecheckErrors = append(typecheckErrors, err) typecheckErrors = append(typecheckErrors, err)
}, },
Importer: newSimpleImporter(), Importer: simpleImporter{},
Sizes: types.SizesFor("gccgo", "arm"), Sizes: types.SizesFor("gccgo", "arm"),
} }
_, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil) _, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil)
@@ -202,33 +202,14 @@ func Test_cgoPackage_isEquivalentAST(t *testing.T) {
} }
// simpleImporter implements the types.Importer interface, but only allows // simpleImporter implements the types.Importer interface, but only allows
// importing the syscall and unsafe packages. // importing the unsafe package.
type simpleImporter struct { type simpleImporter struct {
syscallPkg *types.Package
}
func newSimpleImporter() *simpleImporter {
i := &simpleImporter{}
// Implement a dummy syscall package with the Errno type.
i.syscallPkg = types.NewPackage("syscall", "syscall")
obj := types.NewTypeName(token.NoPos, i.syscallPkg, "Errno", nil)
named := types.NewNamed(obj, nil, nil)
i.syscallPkg.Scope().Insert(obj)
named.SetUnderlying(types.Typ[types.Uintptr])
sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(types.NewParam(token.NoPos, i.syscallPkg, "", types.Typ[types.String])), false)
named.AddMethod(types.NewFunc(token.NoPos, i.syscallPkg, "Error", sig))
i.syscallPkg.MarkComplete()
return i
} }
// Import implements the Importer interface. For testing usage only: it only // Import implements the Importer interface. For testing usage only: it only
// supports importing the unsafe package. // supports importing the unsafe package.
func (i *simpleImporter) Import(path string) (*types.Package, error) { func (i simpleImporter) Import(path string) (*types.Package, error) {
switch path { switch path {
case "syscall":
return i.syscallPkg, nil
case "unsafe": case "unsafe":
return types.Unsafe, nil return types.Unsafe, nil
default: default:
+4 -136
View File
@@ -54,72 +54,8 @@ func init() {
} }
// parseConst parses the given string as a C constant. // parseConst parses the given string as a C constant.
func parseConst(pos token.Pos, fset *token.FileSet, value string, params []ast.Expr, callerPos token.Pos, f *cgoFile) (ast.Expr, *scanner.Error) { func parseConst(pos token.Pos, fset *token.FileSet, value string) (ast.Expr, *scanner.Error) {
t := newTokenizer(pos, fset, value, f) t := newTokenizer(pos, fset, value)
// If params is non-nil (could be a zero length slice), this const is
// actually a function-call like expression from another macro.
// This means we have to parse a string like "(a, b) (a+b)".
// We do this by parsing the parameters at the start and then treating the
// following like a normal constant expression.
if params != nil {
// Parse opening paren.
if t.curToken != token.LPAREN {
return nil, unexpectedToken(t, token.LPAREN)
}
t.Next()
// Parse parameters (identifiers) and closing paren.
var paramIdents []string
for i := 0; ; i++ {
if i == 0 && t.curToken == token.RPAREN {
// No parameters, break early.
t.Next()
break
}
// Read the parameter name.
if t.curToken != token.IDENT {
return nil, unexpectedToken(t, token.IDENT)
}
paramIdents = append(paramIdents, t.curValue)
t.Next()
// Read the next token: either a continuation (comma) or end of list
// (rparen).
if t.curToken == token.RPAREN {
// End of parameter list.
t.Next()
break
} else if t.curToken == token.COMMA {
// Comma, so there will be another parameter name.
t.Next()
} else {
return nil, &scanner.Error{
Pos: t.fset.Position(t.curPos),
Msg: "unexpected token " + t.curToken.String() + " inside macro parameters, expected ',' or ')'",
}
}
}
// Report an error if there is a mismatch in parameter length.
// The error is reported at the location of the closing paren from the
// caller location.
if len(params) != len(paramIdents) {
return nil, &scanner.Error{
Pos: t.fset.Position(callerPos),
Msg: fmt.Sprintf("unexpected number of parameters: expected %d, got %d", len(paramIdents), len(params)),
}
}
// Assign values to the parameters.
// These parameter names are closer in 'scope' than other identifiers so
// will be used first when parsing an identifier.
for i, name := range paramIdents {
t.params[name] = params[i]
}
}
expr, err := parseConstExpr(t, precedenceLowest) expr, err := parseConstExpr(t, precedenceLowest)
t.Next() t.Next()
if t.curToken != token.EOF { if t.curToken != token.EOF {
@@ -160,68 +96,6 @@ func parseConstExpr(t *tokenizer, precedence int) (ast.Expr, *scanner.Error) {
} }
func parseIdent(t *tokenizer) (ast.Expr, *scanner.Error) { func parseIdent(t *tokenizer) (ast.Expr, *scanner.Error) {
// If the identifier is one of the parameters of this function-like macro,
// use the parameter value.
if val, ok := t.params[t.curValue]; ok {
return val, nil
}
if t.f != nil {
// Check whether this identifier is actually a macro "call" with
// parameters. In that case, we should parse the parameters and pass it
// on to a new invocation of parseConst.
if t.peekToken == token.LPAREN {
if cursor, ok := t.f.names[t.curValue]; ok && t.f.isFunctionLikeMacro(cursor) {
// We know the current and peek tokens (the peek one is the '('
// token). So skip ahead until the current token is the first
// unknown token.
t.Next()
t.Next()
// Parse the list of parameters until ')' (rparen) is found.
params := []ast.Expr{}
for i := 0; ; i++ {
if i == 0 && t.curToken == token.RPAREN {
break
}
x, err := parseConstExpr(t, precedenceLowest)
if err != nil {
return nil, err
}
params = append(params, x)
t.Next()
if t.curToken == token.COMMA {
t.Next()
} else if t.curToken == token.RPAREN {
break
} else {
return nil, &scanner.Error{
Pos: t.fset.Position(t.curPos),
Msg: "unexpected token " + t.curToken.String() + ", ',' or ')'",
}
}
}
// Evaluate the macro value and use it as the identifier value.
rparen := t.curPos
pos, text := t.f.getMacro(cursor)
return parseConst(pos, t.fset, text, params, rparen, t.f)
}
}
// Normally the name is something defined in the file (like another
// macro) which we get the declaration from using getASTDeclName.
// This ensures that names that are only referenced inside a macro are
// still getting defined.
if cursor, ok := t.f.names[t.curValue]; ok {
return &ast.Ident{
NamePos: t.curPos,
Name: t.f.getASTDeclName(t.curValue, cursor, false),
}, nil
}
}
// t.f is nil during testing. This is a fallback.
return &ast.Ident{ return &ast.Ident{
NamePos: t.curPos, NamePos: t.curPos,
Name: "C." + t.curValue, Name: "C." + t.curValue,
@@ -290,25 +164,21 @@ func unexpectedToken(t *tokenizer, expected token.Token) *scanner.Error {
// tokenizer reads C source code and converts it to Go tokens. // tokenizer reads C source code and converts it to Go tokens.
type tokenizer struct { type tokenizer struct {
f *cgoFile
curPos, peekPos token.Pos curPos, peekPos token.Pos
fset *token.FileSet fset *token.FileSet
curToken, peekToken token.Token curToken, peekToken token.Token
curValue, peekValue string curValue, peekValue string
buf string buf string
params map[string]ast.Expr
} }
// newTokenizer initializes a new tokenizer, positioned at the first token in // newTokenizer initializes a new tokenizer, positioned at the first token in
// the string. // the string.
func newTokenizer(start token.Pos, fset *token.FileSet, buf string, f *cgoFile) *tokenizer { func newTokenizer(start token.Pos, fset *token.FileSet, buf string) *tokenizer {
t := &tokenizer{ t := &tokenizer{
f: f,
peekPos: start, peekPos: start,
fset: fset, fset: fset,
buf: buf, buf: buf,
peekToken: token.ILLEGAL, peekToken: token.ILLEGAL,
params: make(map[string]ast.Expr),
} }
// Parse the first two tokens (cur and peek). // Parse the first two tokens (cur and peek).
t.Next() t.Next()
@@ -360,7 +230,7 @@ func (t *tokenizer) Next() {
t.peekValue = t.buf[:2] t.peekValue = t.buf[:2]
t.buf = t.buf[2:] t.buf = t.buf[2:]
return return
case c == '(' || c == ')' || c == ',' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '&' || c == '|' || c == '^': case c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '&' || c == '|' || c == '^':
// Single-character tokens. // Single-character tokens.
// TODO: ++ (increment) and -- (decrement) operators. // TODO: ++ (increment) and -- (decrement) operators.
switch c { switch c {
@@ -368,8 +238,6 @@ func (t *tokenizer) Next() {
t.peekToken = token.LPAREN t.peekToken = token.LPAREN
case ')': case ')':
t.peekToken = token.RPAREN t.peekToken = token.RPAREN
case ',':
t.peekToken = token.COMMA
case '+': case '+':
t.peekToken = token.ADD t.peekToken = token.ADD
case '-': case '-':
+1 -1
View File
@@ -59,7 +59,7 @@ func TestParseConst(t *testing.T) {
} { } {
fset := token.NewFileSet() fset := token.NewFileSet()
startPos := fset.AddFile("", -1, 1000).Pos(0) startPos := fset.AddFile("", -1, 1000).Pos(0)
expr, err := parseConst(startPos, fset, tc.C, nil, token.NoPos, nil) expr, err := parseConst(startPos, fset, tc.C)
s := "<invalid>" s := "<invalid>"
if err != nil { if err != nil {
if !strings.HasPrefix(tc.Go, "error: ") { if !strings.HasPrefix(tc.Go, "error: ") {
+68 -109
View File
@@ -63,24 +63,10 @@ long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c); CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c); unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c);
unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c); unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c);
unsigned tinygo_clang_Cursor_isMacroFunctionLike(GoCXCursor c);
// Fix some warnings on Windows ARM. Without the __declspec(dllexport), it gives warnings like this:
// In file included from _cgo_export.c:4:
// cgo-gcc-export-header-prolog:49:34: warning: redeclaration of 'tinygo_clang_globals_visitor' should not add 'dllexport' attribute [-Wdll-attribute-on-redeclaration]
// libclang.go:68:5: note: previous declaration is here
// See: https://github.com/golang/go/issues/49721
#if defined(_WIN32)
#define CGO_DECL // __declspec(dllexport)
#else
#define CGO_DECL
#endif
CGO_DECL
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data); int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
CGO_DECL
int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data); int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
CGO_DECL int tinygo_clang_enum_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
void tinygo_clang_inclusion_visitor(CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data); void tinygo_clang_inclusion_visitor(CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data);
*/ */
import "C" import "C"
@@ -219,7 +205,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c)) numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Fun, Kind: ast.Fun,
Name: "_Cgo_" + name, Name: "C." + name,
} }
exportName := name exportName := name
localName := name localName := name
@@ -257,7 +243,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
}, },
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + localName, Name: "C." + localName,
Obj: obj, Obj: obj,
}, },
Type: &ast.FuncType{ Type: &ast.FuncType{
@@ -269,18 +255,10 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
}, },
}, },
} }
var doc []string
if C.clang_isFunctionTypeVariadic(cursorType) != 0 { if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
doc = append(doc, "//go:variadic")
}
if _, ok := f.noescapingFuncs[name]; ok {
doc = append(doc, "//go:noescape")
f.noescapingFuncs[name].used = true
}
if len(doc) != 0 {
decl.Doc.List = append(decl.Doc.List, &ast.Comment{ decl.Doc.List = append(decl.Doc.List, &ast.Comment{
Slash: pos - 1, Slash: pos - 1,
Text: strings.Join(doc, "\n"), Text: "//go:variadic",
}) })
} }
for i := 0; i < numArgs; i++ { for i := 0; i < numArgs; i++ {
@@ -319,7 +297,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
return decl, stringSignature return decl, stringSignature
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl: case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
typ := f.makeASTRecordType(c, pos) typ := f.makeASTRecordType(c, pos)
typeName := "_Cgo_" + name typeName := "C." + name
typeExpr := typ.typeExpr typeExpr := typ.typeExpr
if typ.unionSize != 0 { if typ.unionSize != 0 {
// Convert to a single-field struct type. // Convert to a single-field struct type.
@@ -340,7 +318,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
obj.Decl = typeSpec obj.Decl = typeSpec
return typeSpec, typ return typeSpec, typ
case C.CXCursor_TypedefDecl: case C.CXCursor_TypedefDecl:
typeName := "_Cgo_" + name typeName := "C." + name
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c) underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Typ, Kind: ast.Typ,
@@ -378,12 +356,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
} }
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Var, Kind: ast.Var,
Name: "_Cgo_" + name, Name: "C." + name,
} }
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "C." + name,
Obj: obj, Obj: obj,
}}, }},
Type: typeExpr, Type: typeExpr,
@@ -392,8 +370,45 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
gen.Specs = append(gen.Specs, valueSpec) gen.Specs = append(gen.Specs, valueSpec)
return gen, nil return gen, nil
case C.CXCursor_MacroDefinition: case C.CXCursor_MacroDefinition:
tokenPos, value := f.getMacro(c) // Extract tokens from the Clang tokenizer.
expr, scannerError := parseConst(tokenPos, f.fset, value, nil, token.NoPos, f) // See: https://stackoverflow.com/a/19074846/559350
sourceRange := C.tinygo_clang_getCursorExtent(c)
tu := C.tinygo_clang_Cursor_getTranslationUnit(c)
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)
}
}
C.clang_disposeTokens(tu, rawTokens, numTokens)
value := sourceBuf.String()
// Try to convert this #define into a Go constant expression.
tokenPos := token.NoPos
if pos != token.NoPos {
tokenPos = pos + token.Pos(len(name))
}
expr, scannerError := parseConst(tokenPos, f.fset, value)
if scannerError != nil { if scannerError != nil {
f.errors = append(f.errors, *scannerError) f.errors = append(f.errors, *scannerError)
return nil, nil return nil, nil
@@ -407,12 +422,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
} }
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Con, Kind: ast.Con,
Name: "_Cgo_" + name, Name: "C." + name,
} }
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "C." + name,
Obj: obj, Obj: obj,
}}, }},
Values: []ast.Expr{expr}, Values: []ast.Expr{expr},
@@ -423,7 +438,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
case C.CXCursor_EnumDecl: case C.CXCursor_EnumDecl:
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Typ, Kind: ast.Typ,
Name: "_Cgo_" + name, Name: "C." + name,
} }
underlying := C.tinygo_clang_getEnumDeclIntegerType(c) underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
// TODO: gc's CGo implementation uses types such as `uint32` for enums // TODO: gc's CGo implementation uses types such as `uint32` for enums
@@ -431,7 +446,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
typeSpec := &ast.TypeSpec{ typeSpec := &ast.TypeSpec{
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "C." + name,
Obj: obj, Obj: obj,
}, },
Assign: pos, Assign: pos,
@@ -454,12 +469,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
} }
obj := &ast.Object{ obj := &ast.Object{
Kind: ast.Con, Kind: ast.Con,
Name: "_Cgo_" + name, Name: "C." + name,
} }
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "C." + name,
Obj: obj, Obj: obj,
}}, }},
Values: []ast.Expr{expr}, Values: []ast.Expr{expr},
@@ -473,62 +488,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
} }
} }
// Return whether this is a macro that's also function-like, like this:
//
// #define add(a, b) (a+b)
func (f *cgoFile) isFunctionLikeMacro(c clangCursor) bool {
if C.tinygo_clang_getCursorKind(c) != C.CXCursor_MacroDefinition {
return false
}
return C.tinygo_clang_Cursor_isMacroFunctionLike(c) != 0
}
// Get the macro value: the position in the source file and the string value of
// the macro.
func (f *cgoFile) getMacro(c clangCursor) (pos token.Pos, value string) {
// Extract tokens from the Clang tokenizer.
// See: https://stackoverflow.com/a/19074846/559350
sourceRange := C.tinygo_clang_getCursorExtent(c)
tu := C.tinygo_clang_Cursor_getTranslationUnit(c)
var rawTokens *C.CXToken
var numTokens C.unsigned
C.clang_tokenize(tu, sourceRange, &rawTokens, &numTokens)
tokens := unsafe.Slice(rawTokens, numTokens)
defer C.clang_disposeTokens(tu, 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)
} 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)
}
}
value = sourceBuf.String()
// Obtain the position of this token. This is the position of the first
// character in the 'value' string and is used to report errors at the
// correct location in the source file.
pos = f.getCursorPosition(c)
return
}
func getString(clangString C.CXString) (s string) { func getString(clangString C.CXString) (s string) {
rawString := C.clang_getCString(clangString) rawString := C.clang_getCString(clangString)
s = C.GoString(rawString) s = C.GoString(rawString)
@@ -745,27 +704,27 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
var typeName string var typeName string
switch typ.kind { switch typ.kind {
case C.CXType_Char_S, C.CXType_Char_U: case C.CXType_Char_S, C.CXType_Char_U:
typeName = "_Cgo_char" typeName = "C.char"
case C.CXType_SChar: case C.CXType_SChar:
typeName = "_Cgo_schar" typeName = "C.schar"
case C.CXType_UChar: case C.CXType_UChar:
typeName = "_Cgo_uchar" typeName = "C.uchar"
case C.CXType_Short: case C.CXType_Short:
typeName = "_Cgo_short" typeName = "C.short"
case C.CXType_UShort: case C.CXType_UShort:
typeName = "_Cgo_ushort" typeName = "C.ushort"
case C.CXType_Int: case C.CXType_Int:
typeName = "_Cgo_int" typeName = "C.int"
case C.CXType_UInt: case C.CXType_UInt:
typeName = "_Cgo_uint" typeName = "C.uint"
case C.CXType_Long: case C.CXType_Long:
typeName = "_Cgo_long" typeName = "C.long"
case C.CXType_ULong: case C.CXType_ULong:
typeName = "_Cgo_ulong" typeName = "C.ulong"
case C.CXType_LongLong: case C.CXType_LongLong:
typeName = "_Cgo_longlong" typeName = "C.longlong"
case C.CXType_ULongLong: case C.CXType_ULongLong:
typeName = "_Cgo_ulonglong" typeName = "C.ulonglong"
case C.CXType_Bool: case C.CXType_Bool:
typeName = "bool" typeName = "bool"
case C.CXType_Float, C.CXType_Double, C.CXType_LongDouble: case C.CXType_Float, C.CXType_Double, C.CXType_LongDouble:
@@ -896,7 +855,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
typeSpelling := getString(C.clang_getTypeSpelling(typ)) typeSpelling := getString(C.clang_getTypeSpelling(typ))
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind)) typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling)) f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
typeName = "_Cgo_<unknown>" typeName = "C.<unknown>"
} }
return &ast.Ident{ return &ast.Ident{
NamePos: pos, NamePos: pos,
@@ -913,7 +872,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
var goName string var goName string
typeSize := C.clang_Type_getSizeOf(underlyingType) typeSize := C.clang_Type_getSizeOf(underlyingType)
switch name { switch name {
case "_Cgo_char": case "C.char":
if typeSize != 1 { if typeSize != 1 {
// This happens for some very special purpose architectures // This happens for some very special purpose architectures
// (DSPs etc.) that are not currently targeted. // (DSPs etc.) that are not currently targeted.
@@ -926,7 +885,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
case C.CXType_Char_U: case C.CXType_Char_U:
goName = "uint8" goName = "uint8"
} }
case "_Cgo_schar", "_Cgo_short", "_Cgo_int", "_Cgo_long", "_Cgo_longlong": case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
switch typeSize { switch typeSize {
case 1: case 1:
goName = "int8" goName = "int8"
@@ -937,7 +896,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
case 8: case 8:
goName = "int64" goName = "int64"
} }
case "_Cgo_uchar", "_Cgo_ushort", "_Cgo_uint", "_Cgo_ulong", "_Cgo_ulonglong": case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
switch typeSize { switch typeSize {
case 1: case 1:
goName = "uint8" goName = "uint8"
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build !byollvm && llvm18 //go:build !byollvm && !llvm15 && !llvm16 && !llvm17
package cgo package cgo
-15
View File
@@ -1,15 +0,0 @@
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17 && !llvm18
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include
#cgo freebsd CFLAGS: -I/usr/local/llvm19/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-19/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@19/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@19/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm19/lib -lclang
*/
import "C"
-4
View File
@@ -84,7 +84,3 @@ unsigned tinygo_clang_Cursor_isAnonymous(CXCursor c) {
unsigned tinygo_clang_Cursor_isBitField(CXCursor c) { unsigned tinygo_clang_Cursor_isBitField(CXCursor c) {
return clang_Cursor_isBitField(c); return clang_Cursor_isBitField(c);
} }
unsigned tinygo_clang_Cursor_isMacroFunctionLike(CXCursor c) {
return clang_Cursor_isMacroFunctionLike(c);
}
+27 -35
View File
@@ -1,54 +1,46 @@
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
-16
View File
@@ -3,26 +3,10 @@ package main
/* /*
#define foo 3 #define foo 3
#define bar foo #define bar foo
#define unreferenced 4
#define referenced unreferenced
#define fnlike() 5
#define fnlike_val fnlike()
#define square(n) (n*n)
#define square_val square(20)
#define add(a, b) (a + b)
#define add_val add(3, 5)
*/ */
import "C" import "C"
const ( const (
Foo = C.foo Foo = C.foo
Bar = C.bar Bar = C.bar
Baz = C.referenced
fnlike = C.fnlike_val
square = C.square_val
add = C.add_val
) )
+29 -42
View File
@@ -1,62 +1,49 @@
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
const _Cgo_foo = 3 const C.foo = 3
const _Cgo_bar = _Cgo_foo const C.bar = C.foo
const _Cgo_unreferenced = 4
const _Cgo_referenced = _Cgo_unreferenced
const _Cgo_fnlike_val = 5
const _Cgo_square_val = (20 * 20)
const _Cgo_add_val = (3 + 5)
-13
View File
@@ -10,11 +10,6 @@ typedef struct {
typedef someType noType; // undefined type typedef someType noType; // undefined type
// Some invalid noescape lines
#cgo noescape
#cgo noescape foo bar
#cgo noescape unusedFunction
#define SOME_CONST_1 5) // invalid const syntax #define SOME_CONST_1 5) // invalid const syntax
#define SOME_CONST_2 6) // const not used (so no error) #define SOME_CONST_2 6) // const not used (so no error)
#define SOME_CONST_3 1234 // const too large for byte #define SOME_CONST_3 1234 // const too large for byte
@@ -31,11 +26,6 @@ import "C"
// #warning another warning // #warning another warning
import "C" import "C"
// #define add(a, b) (a+b)
// #define add_toomuch add(1, 2, 3)
// #define add_toolittle add(1)
import "C"
// Make sure that errors for the following lines won't change with future // Make sure that errors for the following lines won't change with future
// additions to the CGo preamble. // additions to the CGo preamble.
// //
@@ -61,7 +51,4 @@ var (
// constants passed by a command line parameter // constants passed by a command line parameter
_ = C.SOME_PARAM_CONST_invalid _ = C.SOME_PARAM_CONST_invalid
_ = C.SOME_PARAM_CONST_valid _ = C.SOME_PARAM_CONST_valid
_ = C.add_toomuch
_ = C.add_toolittle
) )
+45 -60
View File
@@ -1,89 +1,74 @@
// CGo errors: // CGo errors:
// testdata/errors.go:14:1: missing function name in #cgo noescape line
// testdata/errors.go:15:1: multiple function names in #cgo noescape line
// testdata/errors.go:4:2: warning: some warning // testdata/errors.go:4:2: warning: some warning
// testdata/errors.go:11:9: error: unknown type name 'someType' // testdata/errors.go:11:9: error: unknown type name 'someType'
// testdata/errors.go:31:5: warning: another warning // testdata/errors.go:26:5: warning: another warning
// testdata/errors.go:18:23: unexpected token ), expected end of expression // testdata/errors.go:13:23: unexpected token ), expected end of expression
// testdata/errors.go:26:26: unexpected token ), expected end of expression // testdata/errors.go:21:26: unexpected token ), expected end of expression
// testdata/errors.go:21:33: unexpected token ), expected end of expression // testdata/errors.go:16:33: unexpected token ), expected end of expression
// testdata/errors.go:22:34: unexpected token ), expected end of expression // testdata/errors.go:17:34: unexpected token ), expected end of expression
// -: unexpected token INT, expected end of expression // -: unexpected token INT, expected end of expression
// testdata/errors.go:35:35: unexpected number of parameters: expected 2, got 3
// testdata/errors.go:36:31: unexpected number of parameters: expected 2, got 1
// testdata/errors.go:3:1: function "unusedFunction" in #cgo noescape line is not used
// Type checking errors after CGo processing: // Type checking errors after CGo processing:
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as _Cgo_char value in variable declaration (overflows) // testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
// testdata/errors.go:105: unknown field z in struct literal // testdata/errors.go:105: unknown field z in struct literal
// testdata/errors.go:108: undefined: _Cgo_SOME_CONST_1 // testdata/errors.go:108: undefined: C.SOME_CONST_1
// testdata/errors.go:110: cannot use _Cgo_SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows) // 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: _Cgo_SOME_CONST_4 // testdata/errors.go:112: undefined: C.SOME_CONST_4
// testdata/errors.go:114: undefined: _Cgo_SOME_CONST_b // testdata/errors.go:114: undefined: C.SOME_CONST_b
// testdata/errors.go:116: undefined: _Cgo_SOME_CONST_startspace // testdata/errors.go:116: undefined: C.SOME_CONST_startspace
// testdata/errors.go:119: undefined: _Cgo_SOME_PARAM_CONST_invalid // testdata/errors.go:119: undefined: C.SOME_PARAM_CONST_invalid
// testdata/errors.go:122: undefined: _Cgo_add_toomuch
// testdata/errors.go:123: undefined: _Cgo_add_toolittle
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
type _Cgo_struct_point_t struct { type C.struct_point_t struct {
x _Cgo_int x C.int
y _Cgo_int y C.int
} }
type _Cgo_point_t = _Cgo_struct_point_t type C.point_t = C.struct_point_t
const _Cgo_SOME_CONST_3 = 1234 const C.SOME_CONST_3 = 1234
const _Cgo_SOME_PARAM_CONST_valid = 3 + 4 const C.SOME_PARAM_CONST_valid = 3 + 4
+29 -37
View File
@@ -5,58 +5,50 @@
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
const _Cgo_BAR = 3 const C.BAR = 3
const _Cgo_FOO_H = 1 const C.FOO_H = 1
-5
View File
@@ -9,10 +9,6 @@ static void staticfunc(int x);
// Global variable signatures. // Global variable signatures.
extern int someValue; extern int someValue;
void notEscapingFunction(int *a);
#cgo noescape notEscapingFunction
*/ */
import "C" import "C"
@@ -22,7 +18,6 @@ func accessFunctions() {
C.variadic0() C.variadic0()
C.variadic2(3, 5) C.variadic2(3, 5)
C.staticfunc(3) C.staticfunc(3)
C.notEscapingFunction(nil)
} }
func accessGlobals() { func accessGlobals() {
+36 -49
View File
@@ -1,84 +1,71 @@
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
//export foo //export foo
func _Cgo_foo(a _Cgo_int, b _Cgo_int) _Cgo_int func C.foo(a C.int, b C.int) C.int
var _Cgo_foo$funcaddr unsafe.Pointer var C.foo$funcaddr unsafe.Pointer
//export variadic0 //export variadic0
//go:variadic //go:variadic
func _Cgo_variadic0() func C.variadic0()
var _Cgo_variadic0$funcaddr unsafe.Pointer var C.variadic0$funcaddr unsafe.Pointer
//export variadic2 //export variadic2
//go:variadic //go:variadic
func _Cgo_variadic2(x _Cgo_int, y _Cgo_int) func C.variadic2(x C.int, y C.int)
var _Cgo_variadic2$funcaddr unsafe.Pointer var C.variadic2$funcaddr unsafe.Pointer
//export _Cgo_static_173c95a79b6df1980521_staticfunc //export _Cgo_static_173c95a79b6df1980521_staticfunc
func _Cgo_staticfunc!symbols.go(x _Cgo_int) func C.staticfunc!symbols.go(x C.int)
var _Cgo_staticfunc!symbols.go$funcaddr unsafe.Pointer var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
//export notEscapingFunction
//go:noescape
func _Cgo_notEscapingFunction(a *_Cgo_int)
var _Cgo_notEscapingFunction$funcaddr unsafe.Pointer
//go:extern someValue //go:extern someValue
var _Cgo_someValue _Cgo_int var C.someValue C.int
+95 -107
View File
@@ -1,166 +1,154 @@
package main package main
import "syscall"
import "unsafe" import "unsafe"
var _ unsafe.Pointer var _ unsafe.Pointer
//go:linkname _Cgo_CString runtime.cgo_CString //go:linkname C.CString runtime.cgo_CString
func _Cgo_CString(string) *_Cgo_char func C.CString(string) *C.char
//go:linkname _Cgo_GoString runtime.cgo_GoString //go:linkname C.GoString runtime.cgo_GoString
func _Cgo_GoString(*_Cgo_char) string func C.GoString(*C.char) string
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN //go:linkname C.__GoStringN runtime.cgo_GoStringN
func _Cgo___GoStringN(*_Cgo_char, uintptr) string func C.__GoStringN(*C.char, uintptr) string
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string { func C.GoStringN(cstr *C.char, length C.int) string {
return _Cgo___GoStringN(cstr, uintptr(length)) return C.__GoStringN(cstr, uintptr(length))
} }
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes //go:linkname C.__GoBytes runtime.cgo_GoBytes
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte { func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return _Cgo___GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname _Cgo___CBytes runtime.cgo_CBytes //go:linkname C.__CBytes runtime.cgo_CBytes
func _Cgo___CBytes([]byte) unsafe.Pointer func C.__CBytes([]byte) unsafe.Pointer
func _Cgo_CBytes(b []byte) unsafe.Pointer { func C.CBytes(b []byte) unsafe.Pointer {
return _Cgo___CBytes(b) return C.__CBytes(b)
}
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
func _Cgo___get_errno_num() uintptr
func _Cgo___get_errno() error {
return syscall.Errno(_Cgo___get_errno_num())
} }
type ( type (
_Cgo_char uint8 C.char uint8
_Cgo_schar int8 C.schar int8
_Cgo_uchar uint8 C.uchar uint8
_Cgo_short int16 C.short int16
_Cgo_ushort uint16 C.ushort uint16
_Cgo_int int32 C.int int32
_Cgo_uint uint32 C.uint uint32
_Cgo_long int32 C.long int32
_Cgo_ulong uint32 C.ulong uint32
_Cgo_longlong int64 C.longlong int64
_Cgo_ulonglong uint64 C.ulonglong uint64
) )
type _Cgo_myint = _Cgo_int type C.myint = C.int
type _Cgo_struct_point2d_t struct { type C.struct_point2d_t struct {
x _Cgo_int x C.int
y _Cgo_int y C.int
} }
type _Cgo_point2d_t = _Cgo_struct_point2d_t type C.point2d_t = C.struct_point2d_t
type _Cgo_struct_point3d struct { type C.struct_point3d struct {
x _Cgo_int x C.int
y _Cgo_int y C.int
z _Cgo_int z C.int
} }
type _Cgo_point3d_t = _Cgo_struct_point3d type C.point3d_t = C.struct_point3d
type _Cgo_struct_type1 struct { type C.struct_type1 struct {
_type _Cgo_int _type C.int
__type _Cgo_int __type C.int
___type _Cgo_int ___type C.int
} }
type _Cgo_struct_type2 struct{ _type _Cgo_int } type C.struct_type2 struct{ _type C.int }
type _Cgo_union_union1_t struct{ i _Cgo_int } type C.union_union1_t struct{ i C.int }
type _Cgo_union1_t = _Cgo_union_union1_t type C.union1_t = C.union_union1_t
type _Cgo_union_union3_t struct{ $union uint64 } type C.union_union3_t struct{ $union uint64 }
func (union *_Cgo_union_union3_t) unionfield_i() *_Cgo_int { func (union *C.union_union3_t) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
return (*_Cgo_int)(unsafe.Pointer(&union.$union)) func (union *C.union_union3_t) unionfield_d() *float64 {
}
func (union *_Cgo_union_union3_t) unionfield_d() *float64 {
return (*float64)(unsafe.Pointer(&union.$union)) return (*float64)(unsafe.Pointer(&union.$union))
} }
func (union *_Cgo_union_union3_t) unionfield_s() *_Cgo_short { func (union *C.union_union3_t) unionfield_s() *C.short {
return (*_Cgo_short)(unsafe.Pointer(&union.$union)) return (*C.short)(unsafe.Pointer(&union.$union))
} }
type _Cgo_union3_t = _Cgo_union_union3_t type C.union3_t = C.union_union3_t
type _Cgo_union_union2d struct{ $union [2]uint64 } type C.union_union2d struct{ $union [2]uint64 }
func (union *_Cgo_union_union2d) unionfield_i() *_Cgo_int { func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
return (*_Cgo_int)(unsafe.Pointer(&union.$union)) func (union *C.union_union2d) unionfield_d() *[2]float64 {
}
func (union *_Cgo_union_union2d) unionfield_d() *[2]float64 {
return (*[2]float64)(unsafe.Pointer(&union.$union)) return (*[2]float64)(unsafe.Pointer(&union.$union))
} }
type _Cgo_union2d_t = _Cgo_union_union2d type C.union2d_t = C.union_union2d
type _Cgo_union_unionarray_t struct{ arr [10]_Cgo_uchar } type C.union_unionarray_t struct{ arr [10]C.uchar }
type _Cgo_unionarray_t = _Cgo_union_unionarray_t type C.unionarray_t = C.union_unionarray_t
type _Cgo__Ctype_union___0 struct{ $union [3]uint32 } type C._Ctype_union___0 struct{ $union [3]uint32 }
func (union *_Cgo__Ctype_union___0) unionfield_area() *_Cgo_point2d_t { func (union *C._Ctype_union___0) unionfield_area() *C.point2d_t {
return (*_Cgo_point2d_t)(unsafe.Pointer(&union.$union)) return (*C.point2d_t)(unsafe.Pointer(&union.$union))
} }
func (union *_Cgo__Ctype_union___0) unionfield_solid() *_Cgo_point3d_t { func (union *C._Ctype_union___0) unionfield_solid() *C.point3d_t {
return (*_Cgo_point3d_t)(unsafe.Pointer(&union.$union)) return (*C.point3d_t)(unsafe.Pointer(&union.$union))
} }
type _Cgo_struct_struct_nested_t struct { type C.struct_struct_nested_t struct {
begin _Cgo_point2d_t begin C.point2d_t
end _Cgo_point2d_t end C.point2d_t
tag _Cgo_int tag C.int
coord _Cgo__Ctype_union___0 coord C._Ctype_union___0
} }
type _Cgo_struct_nested_t = _Cgo_struct_struct_nested_t type C.struct_nested_t = C.struct_struct_nested_t
type _Cgo_union_union_nested_t struct{ $union [2]uint64 } type C.union_union_nested_t struct{ $union [2]uint64 }
func (union *_Cgo_union_union_nested_t) unionfield_point() *_Cgo_point3d_t { func (union *C.union_union_nested_t) unionfield_point() *C.point3d_t {
return (*_Cgo_point3d_t)(unsafe.Pointer(&union.$union)) return (*C.point3d_t)(unsafe.Pointer(&union.$union))
} }
func (union *_Cgo_union_union_nested_t) unionfield_array() *_Cgo_unionarray_t { func (union *C.union_union_nested_t) unionfield_array() *C.unionarray_t {
return (*_Cgo_unionarray_t)(unsafe.Pointer(&union.$union)) return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
} }
func (union *_Cgo_union_union_nested_t) unionfield_thing() *_Cgo_union3_t { func (union *C.union_union_nested_t) unionfield_thing() *C.union3_t {
return (*_Cgo_union3_t)(unsafe.Pointer(&union.$union)) return (*C.union3_t)(unsafe.Pointer(&union.$union))
} }
type _Cgo_union_nested_t = _Cgo_union_union_nested_t type C.union_nested_t = C.union_union_nested_t
type _Cgo_enum_option = _Cgo_int type C.enum_option = C.int
type _Cgo_option_t = _Cgo_enum_option type C.option_t = C.enum_option
type _Cgo_enum_option2_t = _Cgo_uint type C.enum_option2_t = C.uint
type _Cgo_option2_t = _Cgo_enum_option2_t type C.option2_t = C.enum_option2_t
type _Cgo_struct_types_t struct { type C.struct_types_t struct {
f float32 f float32
d float64 d float64
ptr *_Cgo_int ptr *C.int
} }
type _Cgo_types_t = _Cgo_struct_types_t type C.types_t = C.struct_types_t
type _Cgo_myIntArray = [10]_Cgo_int type C.myIntArray = [10]C.int
type _Cgo_struct_bitfield_t struct { type C.struct_bitfield_t struct {
start _Cgo_uchar start C.uchar
__bitfield_1 _Cgo_uchar __bitfield_1 C.uchar
d _Cgo_uchar d C.uchar
e _Cgo_uchar e C.uchar
} }
func (s *_Cgo_struct_bitfield_t) bitfield_a() _Cgo_uchar { return s.__bitfield_1 & 0x1f } func (s *C.struct_bitfield_t) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
func (s *_Cgo_struct_bitfield_t) set_bitfield_a(value _Cgo_uchar) { func (s *C.struct_bitfield_t) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0 s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
} }
func (s *_Cgo_struct_bitfield_t) bitfield_b() _Cgo_uchar { func (s *C.struct_bitfield_t) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1 return s.__bitfield_1 >> 5 & 0x1
} }
func (s *_Cgo_struct_bitfield_t) set_bitfield_b(value _Cgo_uchar) { func (s *C.struct_bitfield_t) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5 s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
} }
func (s *_Cgo_struct_bitfield_t) bitfield_c() _Cgo_uchar { func (s *C.struct_bitfield_t) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6 return s.__bitfield_1 >> 6
} }
func (s *_Cgo_struct_bitfield_t) set_bitfield_c(value _Cgo_uchar, func (s *C.struct_bitfield_t) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 } ) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type _Cgo_bitfield_t = _Cgo_struct_bitfield_t type C.bitfield_t = C.struct_bitfield_t
+9 -3
View File
@@ -331,7 +331,6 @@ func (c *Config) CFlags(libclang bool) []string {
"-isystem", filepath.Join(path, "include"), "-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(picolibcDir, "include"), "-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"), "-isystem", filepath.Join(picolibcDir, "tinystdio"),
"-D__PICOLIBC_ERRNO_FUNCTION=__errno_location",
) )
case "musl": case "musl":
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
@@ -341,7 +340,6 @@ func (c *Config) CFlags(libclang bool) []string {
"-nostdlibinc", "-nostdlibinc",
"-isystem", filepath.Join(path, "include"), "-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch), "-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
"-isystem", filepath.Join(root, "lib", "musl", "arch", "generic"),
"-isystem", filepath.Join(root, "lib", "musl", "include"), "-isystem", filepath.Join(root, "lib", "musl", "include"),
) )
case "wasi-libc": case "wasi-libc":
@@ -408,7 +406,15 @@ func (c *Config) LDFlags() []string {
if c.Target.LinkerScript != "" { if c.Target.LinkerScript != "" {
ldflags = append(ldflags, "-T", c.Target.LinkerScript) ldflags = append(ldflags, "-T", c.Target.LinkerScript)
} }
ldflags = append(ldflags, c.Options.ExtLDFlags...)
if c.Options.ExtLDFlags != "" {
ext, err := shlex.Split(c.Options.ExtLDFlags)
if err != nil {
// if shlex can't split it, pass it as-is and let the external linker complain
ext = []string{c.Options.ExtLDFlags}
}
ldflags = append(ldflags, ext...)
}
return ldflags return ldflags
} }
+3 -3
View File
@@ -8,11 +8,11 @@ import (
) )
var ( var (
validBuildModeOptions = []string{"default", "c-shared", "wasi-legacy"} validBuildModeOptions = []string{"default", "c-shared"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"} validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"} validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb", "rtt"} validSerialOptions = []string{"none", "uart", "usb", "rtt"}
validPrintSizeOptions = []string{"none", "short", "full", "html"} validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"} validPanicStrategyOptions = []string{"print", "trap"}
validOptOptions = []string{"none", "0", "1", "2", "s", "z"} validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
) )
@@ -58,7 +58,7 @@ type Options struct {
Timeout time.Duration Timeout time.Duration
WITPackage string // pass through to wasm-tools component embed invocation WITPackage string // pass through to wasm-tools component embed invocation
WITWorld string // pass through to wasm-tools component embed -w option WITWorld string // pass through to wasm-tools component embed -w option
ExtLDFlags []string ExtLDFlags string
} }
// Verify performs a validation on the given options, raising an error if options are not valid. // Verify performs a validation on the given options, raising an error if options are not valid.
+1 -1
View File
@@ -11,7 +11,7 @@ func TestVerifyOptions(t *testing.T) {
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`) expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`) expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full, html`) expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`) expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
testCases := []struct { testCases := []struct {
+4 -9
View File
@@ -46,7 +46,6 @@ type TargetSpec struct {
LinkerScript string `json:"linkerscript,omitempty"` LinkerScript string `json:"linkerscript,omitempty"`
ExtraFiles []string `json:"extra-files,omitempty"` ExtraFiles []string `json:"extra-files,omitempty"`
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
BootPatches []string `json:"boot-patches,omitempty"` // Bootloader patches to be applied in the order they appear.
Emulator string `json:"emulator,omitempty"` Emulator string `json:"emulator,omitempty"`
FlashCommand string `json:"flash-command,omitempty"` FlashCommand string `json:"flash-command,omitempty"`
GDB []string `json:"gdb,omitempty"` GDB []string `json:"gdb,omitempty"`
@@ -328,14 +327,14 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
spec.CPU = "generic" spec.CPU = "generic"
llvmarch = "aarch64" llvmarch = "aarch64"
if options.GOOS == "darwin" { if options.GOOS == "darwin" {
spec.Features = "+ete,+fp-armv8,+neon,+trbe,+v8a" spec.Features = "+fp-armv8,+neon"
// Looks like Apple prefers to call this architecture ARM64 // Looks like Apple prefers to call this architecture ARM64
// instead of AArch64. // instead of AArch64.
llvmarch = "arm64" llvmarch = "arm64"
} else if options.GOOS == "windows" { } else if options.GOOS == "windows" {
spec.Features = "+ete,+fp-armv8,+neon,+trbe,+v8a,-fmv" spec.Features = "+fp-armv8,+neon,-fmv"
} else { // linux } else { // linux
spec.Features = "+ete,+fp-armv8,+neon,+trbe,+v8a,-fmv,-outline-atomics" spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
} }
case "mips", "mipsle": case "mips", "mipsle":
spec.CPU = "mips32" spec.CPU = "mips32"
@@ -358,13 +357,11 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
case "wasm": case "wasm":
llvmarch = "wasm32" llvmarch = "wasm32"
spec.CPU = "generic" spec.CPU = "generic"
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm") spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
spec.CFlags = append(spec.CFlags, spec.CFlags = append(spec.CFlags,
"-mbulk-memory", "-mbulk-memory",
"-mnontrapping-fptoint", "-mnontrapping-fptoint",
"-mno-multivalue",
"-mno-reference-types",
"-msign-ext", "-msign-ext",
) )
default: default:
@@ -393,7 +390,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
"-platform_version", "macos", platformVersion, platformVersion, "-platform_version", "macos", platformVersion, platformVersion,
) )
spec.ExtraFiles = append(spec.ExtraFiles, spec.ExtraFiles = append(spec.ExtraFiles,
"src/internal/futex/futex_darwin.c",
"src/runtime/os_darwin.c", "src/runtime/os_darwin.c",
"src/runtime/runtime_unix.c", "src/runtime/runtime_unix.c",
"src/runtime/signal.c") "src/runtime/signal.c")
@@ -417,7 +413,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics") spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
} }
spec.ExtraFiles = append(spec.ExtraFiles, spec.ExtraFiles = append(spec.ExtraFiles,
"src/internal/futex/futex_linux.c",
"src/runtime/runtime_unix.c", "src/runtime/runtime_unix.c",
"src/runtime/signal.c") "src/runtime/signal.c")
case "windows": case "windows":
+5 -6
View File
@@ -18,12 +18,11 @@ var stdlibAliases = map[string]string{
// crypto packages // crypto packages
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric", "crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
"crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric", "crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
"crypto/md5.block": "crypto/md5.blockGeneric", "crypto/md5.block": "crypto/md5.blockGeneric",
"crypto/sha1.block": "crypto/sha1.blockGeneric", "crypto/sha1.block": "crypto/sha1.blockGeneric",
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric", "crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
"crypto/sha256.block": "crypto/sha256.blockGeneric", "crypto/sha256.block": "crypto/sha256.blockGeneric",
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric", "crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
"internal/chacha8rand.block": "internal/chacha8rand.block_generic",
// AES // AES
"crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock", "crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock",
+11 -11
View File
@@ -31,7 +31,7 @@ func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value) {
// Now do the bounds check: index >= arrayLen // Now do the bounds check: index >= arrayLen
outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "") outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "")
b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", true) b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic")
} }
// createSliceBoundsCheck emits a bounds check before a slicing operation to make // createSliceBoundsCheck emits a bounds check before a slicing operation to make
@@ -74,7 +74,7 @@ func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lo
outOfBounds3 := b.CreateICmp(llvm.IntUGT, max, capacity, "slice.maxcap") outOfBounds3 := b.CreateICmp(llvm.IntUGT, max, capacity, "slice.maxcap")
outOfBounds := b.CreateOr(outOfBounds1, outOfBounds2, "slice.lowmax") outOfBounds := b.CreateOr(outOfBounds1, outOfBounds2, "slice.lowmax")
outOfBounds = b.CreateOr(outOfBounds, outOfBounds3, "slice.lowcap") outOfBounds = b.CreateOr(outOfBounds, outOfBounds3, "slice.lowcap")
b.createRuntimeAssert(outOfBounds, "slice", "slicePanic", false) b.createRuntimeAssert(outOfBounds, "slice", "slicePanic")
} }
// createSliceToArrayPointerCheck adds a check for slice-to-array pointer // createSliceToArrayPointerCheck adds a check for slice-to-array pointer
@@ -86,7 +86,7 @@ func (b *builder) createSliceToArrayPointerCheck(sliceLen llvm.Value, arrayLen i
// > run-time panic occurs. // > run-time panic occurs.
arrayLenValue := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false) arrayLenValue := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false)
isLess := b.CreateICmp(llvm.IntULT, sliceLen, arrayLenValue, "") isLess := b.CreateICmp(llvm.IntULT, sliceLen, arrayLenValue, "")
b.createRuntimeAssert(isLess, "slicetoarray", "sliceToArrayPointerPanic", false) b.createRuntimeAssert(isLess, "slicetoarray", "sliceToArrayPointerPanic")
} }
// createUnsafeSliceStringCheck inserts a runtime check used for unsafe.Slice // createUnsafeSliceStringCheck inserts a runtime check used for unsafe.Slice
@@ -118,7 +118,7 @@ func (b *builder) createUnsafeSliceStringCheck(name string, ptr, len llvm.Value,
lenIsNotZero := b.CreateICmp(llvm.IntNE, len, zero, "") lenIsNotZero := b.CreateICmp(llvm.IntNE, len, zero, "")
assert := b.CreateAnd(ptrIsNil, lenIsNotZero, "") assert := b.CreateAnd(ptrIsNil, lenIsNotZero, "")
assert = b.CreateOr(assert, lenOutOfBounds, "") assert = b.CreateOr(assert, lenOutOfBounds, "")
b.createRuntimeAssert(assert, name, "unsafeSlicePanic", false) b.createRuntimeAssert(assert, name, "unsafeSlicePanic")
} }
// createChanBoundsCheck creates a bounds check before creating a new channel to // createChanBoundsCheck creates a bounds check before creating a new channel to
@@ -155,7 +155,7 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
// Do the check for a too large (or negative) buffer size. // Do the check for a too large (or negative) buffer size.
bufSizeTooBig := b.CreateICmp(llvm.IntUGE, bufSize, maxBufSize, "") bufSizeTooBig := b.CreateICmp(llvm.IntUGE, bufSize, maxBufSize, "")
b.createRuntimeAssert(bufSizeTooBig, "chan", "chanMakePanic", false) b.createRuntimeAssert(bufSizeTooBig, "chan", "chanMakePanic")
} }
// createNilCheck checks whether the given pointer is nil, and panics if it is. // createNilCheck checks whether the given pointer is nil, and panics if it is.
@@ -199,7 +199,7 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
isnil := b.CreateICmp(llvm.IntEQ, ptr, nilptr, "") isnil := b.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
// Emit the nil check in IR. // Emit the nil check in IR.
b.createRuntimeAssert(isnil, blockPrefix, "nilPanic", false) b.createRuntimeAssert(isnil, blockPrefix, "nilPanic")
} }
// createNegativeShiftCheck creates an assertion that panics if the given shift value is negative. // createNegativeShiftCheck creates an assertion that panics if the given shift value is negative.
@@ -212,7 +212,7 @@ func (b *builder) createNegativeShiftCheck(shift llvm.Value) {
// isNegative = shift < 0 // isNegative = shift < 0
isNegative := b.CreateICmp(llvm.IntSLT, shift, llvm.ConstInt(shift.Type(), 0, false), "") isNegative := b.CreateICmp(llvm.IntSLT, shift, llvm.ConstInt(shift.Type(), 0, false), "")
b.createRuntimeAssert(isNegative, "shift", "negativeShiftPanic", false) b.createRuntimeAssert(isNegative, "shift", "negativeShiftPanic")
} }
// createDivideByZeroCheck asserts that y is not zero. If it is, a runtime panic // createDivideByZeroCheck asserts that y is not zero. If it is, a runtime panic
@@ -225,12 +225,12 @@ func (b *builder) createDivideByZeroCheck(y llvm.Value) {
// isZero = y == 0 // isZero = y == 0
isZero := b.CreateICmp(llvm.IntEQ, y, llvm.ConstInt(y.Type(), 0, false), "") isZero := b.CreateICmp(llvm.IntEQ, y, llvm.ConstInt(y.Type(), 0, false), "")
b.createRuntimeAssert(isZero, "divbyzero", "divideByZeroPanic", true) b.createRuntimeAssert(isZero, "divbyzero", "divideByZeroPanic")
} }
// createRuntimeAssert is a common function to create a new branch on an assert // createRuntimeAssert is a common function to create a new branch on an assert
// bool, calling an assert func if the assert value is true (1). // bool, calling an assert func if the assert value is true (1).
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, isInvoke bool) { func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string) {
// Check whether we can resolve this check at compile time. // Check whether we can resolve this check at compile time.
if !assert.IsAConstantInt().IsNil() { if !assert.IsAConstantInt().IsNil() {
val := assert.ZExtValue() val := assert.ZExtValue()
@@ -245,17 +245,17 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
// current insert position. // current insert position.
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw") faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
nextBlock := b.insertBasicBlock(blockPrefix + ".next") nextBlock := b.insertBasicBlock(blockPrefix + ".next")
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block. // Now branch to the out-of-bounds or the regular block.
b.CreateCondBr(assert, faultBlock, nextBlock) b.CreateCondBr(assert, faultBlock, nextBlock)
// Fail: the assert triggered so panic. // Fail: the assert triggered so panic.
b.SetInsertPointAtEnd(faultBlock) b.SetInsertPointAtEnd(faultBlock)
b.createRuntimeCallCommon(assertFunc, nil, "", isInvoke) b.createRuntimeCall(assertFunc, nil, "")
b.CreateUnreachable() b.CreateUnreachable()
// Ok: assert didn't trigger so continue normally. // Ok: assert didn't trigger so continue normally.
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
b.SetInsertPointAtEnd(nextBlock) b.SetInsertPointAtEnd(nextBlock)
} }
+5 -7
View File
@@ -19,9 +19,8 @@ const maxFieldsPerParam = 3
// useful while declaring or defining a function. // useful while declaring or defining a function.
type paramInfo struct { type paramInfo struct {
llvmType llvm.Type llvmType llvm.Type
name string // name, possibly with suffixes for e.g. struct fields name string // name, possibly with suffixes for e.g. struct fields
elemSize uint64 // size of pointer element type, or 0 if this isn't a pointer elemSize uint64 // size of pointer element type, or 0 if this isn't a pointer
flags paramFlags // extra flags for this parameter
} }
// paramFlags identifies parameter attributes for flags. Most importantly, it // paramFlags identifies parameter attributes for flags. Most importantly, it
@@ -29,9 +28,9 @@ type paramInfo struct {
type paramFlags uint8 type paramFlags uint8
const ( const (
// Whether this is a full or partial Go parameter (int, slice, etc). // Parameter may have the deferenceable_or_null attribute. This attribute
// The extra context parameter is not a Go parameter. // cannot be applied to unsafe.Pointer and to the data pointer of slices.
paramIsGoParam = 1 << iota paramIsDeferenceableOrNull = 1 << iota
) )
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or // createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
@@ -196,7 +195,6 @@ func (c *compilerContext) getParamInfo(t llvm.Type, name string, goType types.Ty
info := paramInfo{ info := paramInfo{
llvmType: t, llvmType: t,
name: name, name: name,
flags: paramIsGoParam,
} }
if goType != nil { if goType != nil {
switch underlying := goType.Underlying().(type) { switch underlying := goType.Underlying().(type) {
+17 -36
View File
@@ -4,9 +4,7 @@ package compiler
// or pseudo-operations that are lowered during goroutine lowering. // or pseudo-operations that are lowered during goroutine lowering.
import ( import (
"fmt"
"go/types" "go/types"
"math"
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
@@ -43,17 +41,17 @@ func (b *builder) createChanSend(instr *ssa.Send) {
b.CreateStore(chanValue, valueAlloca) b.CreateStore(chanValue, valueAlloca)
} }
// Allocate buffer for the channel operation. // Allocate blockedlist buffer.
channelOp := b.getLLVMRuntimeType("channelOp") channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op") channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
// Do the send. // Do the send.
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "") b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
// End the lifetime of the allocas. // End the lifetime of the allocas.
// This also works around a bug in CoroSplit, at least in LLVM 8: // This also works around a bug in CoroSplit, at least in LLVM 8:
// https://bugs.llvm.org/show_bug.cgi?id=41742 // https://bugs.llvm.org/show_bug.cgi?id=41742
b.emitLifetimeEnd(channelOpAlloca, channelOpAllocaSize) b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
if !isZeroSize { if !isZeroSize {
b.emitLifetimeEnd(valueAlloca, valueAllocaSize) b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
} }
@@ -74,12 +72,12 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value") valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
} }
// Allocate buffer for the channel operation. // Allocate blockedlist buffer.
channelOp := b.getLLVMRuntimeType("channelOp") channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op") channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
// Do the receive. // Do the receive.
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "") commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
var received llvm.Value var received llvm.Value
if isZeroSize { if isZeroSize {
received = llvm.ConstNull(valueType) received = llvm.ConstNull(valueType)
@@ -87,7 +85,7 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
received = b.CreateLoad(valueType, valueAlloca, "chan.received") received = b.CreateLoad(valueType, valueAlloca, "chan.received")
b.emitLifetimeEnd(valueAlloca, valueAllocaSize) b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
} }
b.emitLifetimeEnd(channelOpAlloca, channelOpAllocaSize) b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
if unop.CommaOk { if unop.CommaOk {
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{valueType, b.ctx.Int1Type()}, false)) tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{valueType, b.ctx.Int1Type()}, false))
@@ -126,20 +124,6 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
} }
} }
const maxSelectStates = math.MaxUint32 >> 2
if len(expr.States) > maxSelectStates {
// The runtime code assumes that the number of state must fit in 30 bits
// (so the select index can be stored in a uint32 with two bits reserved
// for other purposes). It seems unlikely that a real program would have
// that many states, but we check for this case anyway to be sure.
// We use a uint32 (and not a uintptr or uint64) to avoid 64-bit atomic
// operations which aren't available everywhere.
b.addError(expr.Pos(), fmt.Sprintf("too many select states: got %d but the maximum supported number is %d", len(expr.States), maxSelectStates))
// Continue as usual (we'll generate broken code but the error will
// prevent the compilation to complete).
}
// This code create a (stack-allocated) slice containing all the select // This code create a (stack-allocated) slice containing all the select
// cases and then calls runtime.chanSelect to perform the actual select // cases and then calls runtime.chanSelect to perform the actual select
// statement. // statement.
@@ -214,10 +198,10 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
if expr.Blocking { if expr.Blocking {
// Stack-allocate operation structures. // Stack-allocate operation structures.
// If these were simply created as a slice, they would heap-allocate. // If these were simply created as a slice, they would heap-allocate.
opsAllocaType := llvm.ArrayType(b.getLLVMRuntimeType("channelOp"), len(selectStates)) chBlockAllocaType := llvm.ArrayType(b.getLLVMRuntimeType("channelBlockedList"), len(selectStates))
opsAlloca, opsSize := b.createTemporaryAlloca(opsAllocaType, "select.block.alloca") chBlockAlloca, chBlockSize := b.createTemporaryAlloca(chBlockAllocaType, "select.block.alloca")
opsLen := llvm.ConstInt(b.uintptrType, uint64(len(selectStates)), false) chBlockLen := llvm.ConstInt(b.uintptrType, uint64(len(selectStates)), false)
opsPtr := b.CreateGEP(opsAllocaType, opsAlloca, []llvm.Value{ chBlockPtr := b.CreateGEP(chBlockAllocaType, chBlockAlloca, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false), llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 0, false), llvm.ConstInt(b.ctx.Int32Type(), 0, false),
}, "select.block") }, "select.block")
@@ -225,18 +209,15 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
results = b.createRuntimeCall("chanSelect", []llvm.Value{ results = b.createRuntimeCall("chanSelect", []llvm.Value{
recvbuf, recvbuf,
statesPtr, statesLen, statesLen, // []chanSelectState statesPtr, statesLen, statesLen, // []chanSelectState
opsPtr, opsLen, opsLen, // []channelOp chBlockPtr, chBlockLen, chBlockLen, // []channelBlockList
}, "select.result") }, "select.result")
// Terminate the lifetime of the operation structures. // Terminate the lifetime of the operation structures.
b.emitLifetimeEnd(opsAlloca, opsSize) b.emitLifetimeEnd(chBlockAlloca, chBlockSize)
} else { } else {
opsPtr := llvm.ConstNull(b.dataPtrType) results = b.createRuntimeCall("tryChanSelect", []llvm.Value{
opsLen := llvm.ConstInt(b.uintptrType, 0, false)
results = b.createRuntimeCall("chanSelect", []llvm.Value{
recvbuf, recvbuf,
statesPtr, statesLen, statesLen, // []chanSelectState statesPtr, statesLen, statesLen, // []chanSelectState
opsPtr, opsLen, opsLen, // []channelOp (nil slice)
}, "select.result") }, "select.result")
} }
+3 -9
View File
@@ -17,7 +17,6 @@ import (
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/go/types/typeutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
@@ -1681,12 +1680,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
result = b.CreateSelect(cmp, result, arg, "") result = b.CreateSelect(cmp, result, arg, "")
} }
return result, nil return result, nil
case "panic":
// This is rare, but happens in "defer panic()".
b.createRuntimeInvoke("_panic", argValues, "")
return llvm.Value{}, nil
case "print", "println": case "print", "println":
b.createRuntimeCall("printlock", nil, "")
for i, value := range argValues { for i, value := range argValues {
if i >= 1 && callName == "println" { if i >= 1 && callName == "println" {
b.createRuntimeCall("printspace", nil, "") b.createRuntimeCall("printspace", nil, "")
@@ -1747,7 +1741,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
if callName == "println" { if callName == "println" {
b.createRuntimeCall("printnl", nil, "") b.createRuntimeCall("printnl", nil, "")
} }
b.createRuntimeCall("printunlock", nil, "")
return llvm.Value{}, nil // print() or println() returns void return llvm.Value{}, nil // print() or println() returns void
case "real": case "real":
cplx := argValues[0] cplx := argValues[0]
@@ -1872,9 +1865,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
} }
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
case name == "runtime.panicStrategy": case name == "runtime.panicStrategy":
// These constants are defined in src/runtime/panic.go.
panicStrategy := map[string]uint64{ panicStrategy := map[string]uint64{
"print": tinygo.PanicStrategyPrint, "print": 1, // panicStrategyPrint
"trap": tinygo.PanicStrategyTrap, "trap": 2, // panicStrategyTrap
}[b.Config.PanicStrategy] }[b.Config.PanicStrategy]
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
case name == "runtime/interrupt.New": case name == "runtime/interrupt.New":
+1 -1
View File
@@ -161,7 +161,7 @@ str x2, [x1, #8]
mov x0, #0 mov x0, #0
1: 1:
` `
constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{memory}" constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{vg},~{memory}"
if b.GOOS != "darwin" && b.GOOS != "windows" { if b.GOOS != "darwin" && b.GOOS != "windows" {
// These registers cause the following warning when compiling for // These registers cause the following warning when compiling for
// MacOS and Windows: // MacOS and Windows:
-3
View File
@@ -41,8 +41,6 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
// Create a new global of type runtime/interrupt.handle. Globals of this // Create a new global of type runtime/interrupt.handle. Globals of this
// type are lowered in the interrupt lowering pass. // type are lowered in the interrupt lowering pass.
// It must have an alignment of 1, otherwise LLVM thinks a ptrtoint of the
// global has the lower bits unset.
globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type() globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type()
globalLLVMType := b.getLLVMType(globalType) globalLLVMType := b.getLLVMType(globalType)
globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10) globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10)
@@ -50,7 +48,6 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
global.SetVisibility(llvm.HiddenVisibility) global.SetVisibility(llvm.HiddenVisibility)
global.SetGlobalConstant(true) global.SetGlobalConstant(true)
global.SetUnnamedAddr(true) global.SetUnnamedAddr(true)
global.SetAlignment(1)
initializer := llvm.ConstNull(globalLLVMType) initializer := llvm.ConstNull(globalLLVMType)
initializer = b.CreateInsertValue(initializer, funcContext, 0, "") initializer = b.CreateInsertValue(initializer, funcContext, 0, "")
initializer = b.CreateInsertValue(initializer, funcPtr, 1, "") initializer = b.CreateInsertValue(initializer, funcPtr, 1, "")
+11 -5
View File
@@ -6,11 +6,17 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
// constants for hashmap algorithms; must match src/runtime/hashmap.go
const (
hashmapAlgorithmBinary = iota
hashmapAlgorithmString
hashmapAlgorithmInterface
)
// createMakeMap creates a new map object (runtime.hashmap) by allocating and // createMakeMap creates a new map object (runtime.hashmap) by allocating and
// initializing an appropriately sized object. // initializing an appropriately sized object.
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) { func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
@@ -18,20 +24,20 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
keyType := mapType.Key().Underlying() keyType := mapType.Key().Underlying()
llvmValueType := b.getLLVMType(mapType.Elem().Underlying()) llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
var llvmKeyType llvm.Type var llvmKeyType llvm.Type
var alg uint64 var alg uint64 // must match values in src/runtime/hashmap.go
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// String keys. // String keys.
llvmKeyType = b.getLLVMType(keyType) llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmString) alg = hashmapAlgorithmString
} else if hashmapIsBinaryKey(keyType) { } else if hashmapIsBinaryKey(keyType) {
// Trivially comparable keys. // Trivially comparable keys.
llvmKeyType = b.getLLVMType(keyType) llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmBinary) alg = hashmapAlgorithmBinary
} else { } else {
// All other keys. Implemented as map[interface{}]valueType for ease of // All other keys. Implemented as map[interface{}]valueType for ease of
// implementation. // implementation.
llvmKeyType = b.getLLVMRuntimeType("_interface") llvmKeyType = b.getLLVMRuntimeType("_interface")
alg = uint64(tinygo.HashmapAlgorithmInterface) alg = hashmapAlgorithmInterface
} }
keySize := b.targetData.TypeAllocSize(llvmKeyType) keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType) valueSize := b.targetData.TypeAllocSize(llvmValueType)
+11 -48
View File
@@ -33,7 +33,6 @@ type functionInfo struct {
exported bool // go:export, CGo exported bool // go:export, CGo
interrupt bool // go:interrupt interrupt bool // go:interrupt
nobounds bool // go:nobounds nobounds bool // go:nobounds
noescape bool // go:noescape
variadic bool // go:variadic (CGo only) variadic bool // go:variadic (CGo only)
inline inlineType // go:inline inline inlineType // go:inline
} }
@@ -128,20 +127,11 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
c.addStandardDeclaredAttributes(llvmFn) c.addStandardDeclaredAttributes(llvmFn)
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null") dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
for i, paramInfo := range paramInfos { for i, info := range paramInfos {
if paramInfo.elemSize != 0 { if info.elemSize != 0 {
dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, paramInfo.elemSize) dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, info.elemSize)
llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull) llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull)
} }
if info.noescape && paramInfo.flags&paramIsGoParam != 0 && paramInfo.llvmType.TypeKind() == llvm.PointerTypeKind {
// Parameters to functions with a //go:noescape parameter should get
// the nocapture attribute. However, the context parameter should
// not.
// (It may be safe to add the nocapture parameter to the context
// parameter, but I'd like to stay on the safe side here).
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
llvmFn.AddAttributeAtIndex(i+1, nocapture)
}
} }
// Set a number of function or parameter attributes, depending on the // Set a number of function or parameter attributes, depending on the
@@ -231,15 +221,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
} }
} }
// Build the function if needed.
c.maybeCreateSyntheticFunction(fn, llvmFn)
return fnType, llvmFn
}
// If this is a synthetic function (such as a generic function or a wrapper),
// create it now.
func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn llvm.Value) {
// Synthetic functions are functions that do not appear in the source code, // Synthetic functions are functions that do not appear in the source code,
// they are artificially constructed. Usually they are wrapper functions // they are artificially constructed. Usually they are wrapper functions
// that are not referenced anywhere except in a SSA call instruction so // that are not referenced anywhere except in a SSA call instruction so
@@ -247,10 +228,6 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
// The exception is the package initializer, which does appear in the // The exception is the package initializer, which does appear in the
// *ssa.Package members and so shouldn't be created here. // *ssa.Package members and so shouldn't be created here.
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" { if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
if len(fn.Blocks) == 0 {
c.addError(fn.Pos(), "missing function body")
return
}
irbuilder := c.ctx.NewBuilder() irbuilder := c.ctx.NewBuilder()
b := newBuilder(c, irbuilder, fn) b := newBuilder(c, irbuilder, fn)
b.createFunction() b.createFunction()
@@ -258,6 +235,8 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage) llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
llvmFn.SetUnnamedAddr(true) llvmFn.SetUnnamedAddr(true)
} }
return fnType, llvmFn
} }
// getFunctionInfo returns information about a function that is not directly // getFunctionInfo returns information about a function that is not directly
@@ -283,11 +262,6 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
info.wasmName = "_start" info.wasmName = "_start"
info.exported = true info.exported = true
} }
if info.linkName == "runtime.wasmEntryLegacy" && c.BuildMode == "wasi-legacy" {
info.linkName = "_start"
info.wasmName = "_start"
info.exported = true
}
// Check for //go: pragmas, which may change the link name (among others). // Check for //go: pragmas, which may change the link name (among others).
c.parsePragmas(&info, f) c.parsePragmas(&info, f)
@@ -371,7 +345,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
continue continue
} }
if len(parts) != 2 { if len(parts) != 2 {
c.addError(f.Pos(), fmt.Sprintf("expected one parameter to //go:wasmexport, not %d", len(parts)-1)) c.addError(f.Pos(), fmt.Sprintf("expected one parameter to //go:wasmimport, not %d", len(parts)-1))
continue continue
} }
name := parts[1] name := parts[1]
@@ -420,20 +394,14 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
if hasUnsafeImport(f.Pkg.Pkg) { if hasUnsafeImport(f.Pkg.Pkg) {
info.nobounds = true info.nobounds = true
} }
case "//go:noescape":
// Don't let pointer parameters escape.
// Following the upstream Go implementation, we only do this for
// declarations, not definitions.
if len(f.Blocks) == 0 {
info.noescape = true
}
case "//go:variadic": case "//go:variadic":
// The //go:variadic pragma is emitted by the CGo preprocessing // The //go:variadic pragma is emitted by the CGo preprocessing
// pass for C variadic functions. This includes both explicit // pass for C variadic functions. This includes both explicit
// (with ...) and implicit (no parameters in signature) // (with ...) and implicit (no parameters in signature)
// functions. // functions.
if strings.HasPrefix(f.Name(), "_Cgo_") { if strings.HasPrefix(f.Name(), "C.") {
// This prefix was created as a result of CGo preprocessing. // This prefix cannot naturally be created, it must have
// been created as a result of CGo preprocessing.
info.variadic = true info.variadic = true
} }
} }
@@ -688,25 +656,20 @@ func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
// Check for //go: pragmas, which may change the link name (among others). // Check for //go: pragmas, which may change the link name (among others).
doc := c.astComments[info.linkName] doc := c.astComments[info.linkName]
if doc != nil { if doc != nil {
info.parsePragmas(doc, g) info.parsePragmas(doc)
} }
return info return info
} }
// Parse //go: pragma comments from the source. In particular, it parses the // Parse //go: pragma comments from the source. In particular, it parses the
// //go:extern pragma on globals. // //go:extern pragma on globals.
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, g *ssa.Global) { func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
for _, comment := range doc.List { for _, comment := range doc.List {
if !strings.HasPrefix(comment.Text, "//go:") { if !strings.HasPrefix(comment.Text, "//go:") {
continue continue
} }
parts := strings.Fields(comment.Text) parts := strings.Fields(comment.Text)
switch parts[0] { switch parts[0] {
case "//go:linkname":
if len(parts) == 3 && g.Name() == parts[1] {
info.linkName = parts[2]
info.extern = true
}
case "//go:extern": case "//go:extern":
info.extern = true info.extern = true
if len(parts) == 2 { if len(parts) == 2 {
+3 -3
View File
@@ -206,7 +206,7 @@ entry:
ret void ret void
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+32 -32
View File
@@ -3,7 +3,7 @@ source_filename = "channel.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
%runtime.channelOp = type { ptr, ptr, i32, ptr } %runtime.channelBlockedList = type { ptr, ptr, ptr, { ptr, i32, i32 } }
%runtime.chanSelectState = type { ptr, ptr } %runtime.chanSelectState = type { ptr, ptr }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) ; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -18,15 +18,15 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 { define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4 %chan.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
store i32 3, ptr %chan.value, align 4 store i32 3, ptr %chan.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4 call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
ret void ret void
} }
@@ -34,61 +34,61 @@ entry:
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3 declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1 declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3 declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 { define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4 %chan.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4 %0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
ret void ret void
} }
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1 declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 { define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.blockedList = alloca %runtime.channelBlockedList, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4 call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 { define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.blockedList = alloca %runtime.channelBlockedList, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4 %0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #2 { define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #2 {
entry: entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8 %select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4 %select.send.value = alloca i32, align 4
store i32 1, ptr %select.send.value, align 4 store i32 1, ptr %select.send.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca) call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
store ptr %ch1, ptr %select.states.alloca, align 4 store ptr %ch1, ptr %select.states.alloca, align 4
%select.states.alloca.repack1 = getelementptr inbounds i8, ptr %select.states.alloca, i32 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 store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
%0 = getelementptr inbounds i8, ptr %select.states.alloca, i32 8 %0 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1
store ptr %ch2, ptr %0, align 4 store ptr %ch2, ptr %0, align 4
%.repack3 = getelementptr inbounds i8, ptr %select.states.alloca, i32 12 %.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
store ptr null, ptr %.repack3, align 4 store ptr null, ptr %.repack3, align 4
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #4 %select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
%1 = extractvalue { i32, i1 } %select.result, 0 %1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0 %2 = icmp eq i32 %1, 0
@@ -105,10 +105,10 @@ select.body: ; preds = %select.next
br label %select.done br label %select.done
} }
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1 declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #1
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind } attributes #4 = { nounwind }
+12 -21
View File
@@ -3,8 +3,9 @@ source_filename = "defer.go"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7m-unknown-unknown-eabi" target triple = "thumbv7m-unknown-unknown-eabi"
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface } %runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i1, %runtime._interface }
%runtime._interface = type { ptr, ptr } %runtime._interface = type { ptr, ptr }
%runtime._defer = type { i32, ptr }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) ; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
@@ -27,7 +28,7 @@ entry:
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4 store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack15 = getelementptr inbounds i8, ptr %defer.alloca, i32 4 %defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
store ptr null, ptr %defer.alloca.repack15, align 4 store ptr null, ptr %defer.alloca.repack15, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4 store ptr %defer.alloca, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5 %setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
@@ -51,7 +52,7 @@ rundefers.loophead: ; preds = %3, %rundefers.block
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4 %stack.next.gep = getelementptr inbounds %runtime._defer, ptr %2, i32 0, i32 1
%stack.next = load ptr, ptr %stack.next.gep, align 4 %stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4 store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4 %callback = load i32, ptr %2, align 4
@@ -87,7 +88,7 @@ rundefers.loophead6: ; preds = %5, %lpad
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5 br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
rundefers.loop5: ; preds = %rundefers.loophead6 rundefers.loop5: ; preds = %rundefers.loophead6
%stack.next.gep8 = getelementptr inbounds i8, ptr %4, i32 4 %stack.next.gep8 = getelementptr inbounds %runtime._defer, ptr %4, i32 0, i32 1
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4 %stack.next9 = load ptr, ptr %stack.next.gep8, align 4
store ptr %stack.next9, ptr %deferPtr, align 4 store ptr %stack.next9, ptr %deferPtr, align 4
%callback11 = load i32, ptr %4, align 4 %callback11 = load i32, ptr %4, align 4
@@ -121,18 +122,12 @@ declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 { define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
call void @runtime.printunlock(ptr undef) #4
ret void ret void
} }
declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #2 declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 { define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
entry: entry:
@@ -144,11 +139,11 @@ entry:
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4 store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack22 = getelementptr inbounds i8, ptr %defer.alloca, i32 4 %defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
store ptr null, ptr %defer.alloca.repack22, align 4 store ptr null, ptr %defer.alloca.repack22, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4 store ptr %defer.alloca, ptr %deferPtr, align 4
store i32 1, ptr %defer.alloca2, align 4 store i32 1, ptr %defer.alloca2, align 4
%defer.alloca2.repack23 = getelementptr inbounds i8, ptr %defer.alloca2, i32 4 %defer.alloca2.repack23 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca2, i32 0, i32 1
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4 store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
store ptr %defer.alloca2, ptr %deferPtr, align 4 store ptr %defer.alloca2, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5 %setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
@@ -172,7 +167,7 @@ rundefers.loophead: ; preds = %4, %3, %rundefers.b
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4 %stack.next.gep = getelementptr inbounds %runtime._defer, ptr %2, i32 0, i32 1
%stack.next = load ptr, ptr %stack.next.gep, align 4 %stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4 store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4 %callback = load i32, ptr %2, align 4
@@ -218,7 +213,7 @@ rundefers.loophead10: ; preds = %7, %6, %lpad
br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9 br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9
rundefers.loop9: ; preds = %rundefers.loophead10 rundefers.loop9: ; preds = %rundefers.loophead10
%stack.next.gep12 = getelementptr inbounds i8, ptr %5, i32 4 %stack.next.gep12 = getelementptr inbounds %runtime._defer, ptr %5, i32 0, i32 1
%stack.next13 = load ptr, ptr %stack.next.gep12, align 4 %stack.next13 = load ptr, ptr %stack.next.gep12, align 4
store ptr %stack.next13, ptr %deferPtr, align 4 store ptr %stack.next13, ptr %deferPtr, align 4
%callback15 = load i32, ptr %5, align 4 %callback15 = load i32, ptr %5, align 4
@@ -255,24 +250,20 @@ rundefers.end7: ; preds = %rundefers.loophead1
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 { define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
call void @runtime.printunlock(ptr undef) #4
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 { define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #4 call void @runtime.printint32(i32 5, ptr undef) #4
call void @runtime.printunlock(ptr undef) #4
ret void ret void
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #3 = { nocallback nofree nosync nounwind willreturn } attributes #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { nounwind } attributes #4 = { nounwind }
attributes #5 = { nounwind returns_twice } attributes #5 = { nounwind returns_twice }
+3 -3
View File
@@ -93,6 +93,6 @@ entry:
ret i8 %0 ret i8 %0
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
+3 -3
View File
@@ -44,7 +44,7 @@ entry:
ret void ret void
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+10 -10
View File
@@ -105,18 +105,18 @@ entry:
%makeslice = call align 1 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 call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice, ptr @main.slice1, align 4 store ptr %makeslice, ptr @main.slice1, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 4), 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 (i8, ptr @main.slice1, i32 8), align 4 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 %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 call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice1, ptr @main.slice2, align 4 store ptr %makeslice1, ptr @main.slice2, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 4), 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 (i8, ptr @main.slice2, i32 8), align 4 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 %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 call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice3, ptr @main.slice3, align 4 store ptr %makeslice3, ptr @main.slice3, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 4), 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 (i8, ptr @main.slice3, i32 8), align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 4
ret void ret void
} }
@@ -127,7 +127,7 @@ entry:
%0 = call align 8 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 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
store double %v.r, ptr %0, align 8 store double %v.r, ptr %0, align 8
%.repack1 = getelementptr inbounds i8, ptr %0, i32 8 %.repack1 = getelementptr inbounds { double, double }, ptr %0, i32 0, i32 1
store double %v.i, ptr %.repack1, align 8 store double %v.i, ptr %.repack1, align 8
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1 %1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3 call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
@@ -135,7 +135,7 @@ entry:
ret %runtime._interface %1 ret %runtime._interface %1
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+4 -4
View File
@@ -36,7 +36,7 @@ entry:
br i1 %4, label %unsafe.String.throw, label %unsafe.String.next br i1 %4, label %unsafe.String.throw, label %unsafe.String.next
unsafe.String.next: ; preds = %entry unsafe.String.next: ; preds = %entry
%5 = zext nneg i16 %len to i32 %5 = zext i16 %len to i32
%6 = insertvalue %runtime._string undef, ptr %ptr, 0 %6 = insertvalue %runtime._string undef, ptr %ptr, 0
%7 = insertvalue %runtime._string %6, i32 %5, 1 %7 = insertvalue %runtime._string %6, i32 %5, 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
@@ -57,7 +57,7 @@ entry:
ret ptr %s.data ret ptr %s.data
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+3 -3
View File
@@ -171,9 +171,9 @@ declare i32 @llvm.smax.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #4 declare i32 @llvm.umax.i32(i32, i32) #4
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) } attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #5 = { nounwind } attributes #5 = { nounwind }
+23 -29
View File
@@ -65,14 +65,12 @@ entry:
store i32 3, ptr %n, align 4 store i32 3, ptr %n, align 4
%0 = call align 4 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 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
store ptr %n, ptr %1, align 4 store ptr %n, ptr %1, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
%2 = load i32, ptr %n, align 4 %2 = load i32, ptr %n, align 4
call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9 call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #9
ret void ret void
} }
@@ -87,26 +85,22 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 { define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry: entry:
%1 = load i32, ptr %0, align 4 %1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3) call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
ret void ret void
} }
declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #2 declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 { define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry: entry:
%0 = call align 4 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 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
store ptr %fn.context, ptr %1, align 4 store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8 %2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
store ptr %fn.funcptr, ptr %2, align 4 store ptr %fn.funcptr, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
@@ -117,9 +111,9 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 { define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry: entry:
%1 = load i32, ptr %0, align 4 %1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8 %4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
%5 = load ptr, ptr %4, align 4 %5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9 call void %5(i32 %1, ptr %3) #9
ret void ret void
@@ -141,24 +135,24 @@ entry:
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2 declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #9 call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void ret void
} }
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #2 declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry: entry:
%0 = call align 4 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 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8 %2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
store i32 4, ptr %2, align 4 store i32 4, ptr %2, align 4
%3 = getelementptr inbounds i8, ptr %0, i32 12 %3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %3, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
@@ -171,23 +165,23 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 { define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry: entry:
%1 = load ptr, ptr %0, align 4 %1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8 %4 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
%5 = load i32, ptr %4, align 4 %5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds i8, ptr %0, i32 12 %6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
%7 = load ptr, ptr %6, align 4 %7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9 call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
ret void ret void
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" } attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" } attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" } attributes #6 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
attributes #7 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" } attributes #7 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" } attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #9 = { nounwind } attributes #9 = { nounwind }
+23 -29
View File
@@ -72,13 +72,11 @@ entry:
%0 = call align 4 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 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
store ptr %n, ptr %1, align 4 store ptr %n, ptr %1, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
%2 = load i32, ptr %n, align 4 %2 = load i32, ptr %n, align 4
call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9 call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #9
ret void ret void
} }
@@ -93,19 +91,15 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 { define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry: entry:
%1 = load i32, ptr %0, align 4 %1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3) call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
call void @runtime.deadlock(ptr undef) #9 call void @runtime.deadlock(ptr undef) #9
unreachable unreachable
} }
declare void @runtime.printlock(ptr) #1
declare void @runtime.printint32(i32, ptr) #1 declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printunlock(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 { define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
entry: entry:
@@ -113,9 +107,9 @@ entry:
%0 = call align 4 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 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
store ptr %fn.context, ptr %1, align 4 store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8 %2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
store ptr %fn.funcptr, ptr %2, align 4 store ptr %fn.funcptr, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void ret void
@@ -125,9 +119,9 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 { define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry: entry:
%1 = load i32, ptr %0, align 4 %1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8 %4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
%5 = load ptr, ptr %4, align 4 %5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9 call void %5(i32 %1, ptr %3) #9
call void @runtime.deadlock(ptr undef) #9 call void @runtime.deadlock(ptr undef) #9
@@ -150,13 +144,13 @@ entry:
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1 declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 { define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #9 call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void ret void
} }
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1 declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
@@ -165,11 +159,11 @@ entry:
%0 = call align 4 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 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store ptr %itf.value, ptr %0, align 4 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4 %1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8 %2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
store i32 4, ptr %2, align 4 store i32 4, ptr %2, align 4
%3 = getelementptr inbounds i8, ptr %0, i32 12 %3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %3, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void ret void
@@ -181,24 +175,24 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 { define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry: entry:
%1 = load ptr, ptr %0, align 4 %1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4 %2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8 %4 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
%5 = load i32, ptr %4, align 4 %5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds i8, ptr %0, i32 12 %6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
%7 = load ptr, ptr %6, align 4 %7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9 call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
call void @runtime.deadlock(ptr undef) #9 call void @runtime.deadlock(ptr undef) #9
unreachable unreachable
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" } attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" } attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" } attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" } attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" } attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #9 = { nounwind } attributes #9 = { nounwind }
+7 -7
View File
@@ -130,11 +130,11 @@ entry:
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) #6
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" } 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,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() 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,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" } 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,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" } 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 #7 = { nounwind }
+3 -3
View File
@@ -44,7 +44,7 @@ entry:
ret ptr %x ret ptr %x
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
-15
View File
@@ -2,12 +2,6 @@ package main
import _ "unsafe" import _ "unsafe"
// Use the go:linkname mechanism to link this global to a different package.
// This is used in math/bits.
//
//go:linkname linknamedGlobal runtime.testLinknamedGlobal
var linknamedGlobal int
// Creates an external global with name extern_global. // Creates an external global with name extern_global.
// //
//go:extern extern_global //go:extern extern_global
@@ -112,12 +106,3 @@ var undefinedGlobalNotInSection uint32
//go:align 1024 //go:align 1024
//go:section .global_section //go:section .global_section
var multipleGlobalPragmas uint32 var multipleGlobalPragmas uint32
//go:noescape
func doesNotEscapeParam(a *int, b []int, c chan int, d *[0]byte)
// The //go:noescape pragma only works on declarations, not definitions.
//
//go:noescape
func stillEscapes(a *int, b []int, c chan int, d *[0]byte) {
}
+10 -19
View File
@@ -3,7 +3,6 @@ source_filename = "pragma.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
@runtime.testLinknamedGlobal = external global i32, align 4
@extern_global = external global [0 x i8], align 1 @extern_global = external global [0 x i8], align 1
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32 @main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16 @main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
@@ -86,21 +85,13 @@ entry:
declare void @main.undefinedFunctionNotInSection(ptr) #1 declare void @main.undefinedFunctionNotInSection(ptr) #1
declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #1 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" }
; Function Attrs: nounwind attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
define hidden void @main.stillEscapes(ptr dereferenceable_or_null(4) %a, ptr %b.data, i32 %b.len, i32 %b.cap, ptr dereferenceable_or_null(36) %c, ptr %d, ptr %context) unnamed_addr #2 { attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
entry: attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
ret void attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
} attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
+7 -7
View File
@@ -51,9 +51,9 @@ entry:
%varargs = call align 4 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 call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
store i32 1, ptr %varargs, align 4 store i32 1, ptr %varargs, align 4
%0 = getelementptr inbounds i8, ptr %varargs, i32 4 %0 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 1
store i32 2, ptr %0, align 4 store i32 2, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %varargs, i32 8 %1 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 2
store i32 3, ptr %1, align 4 store i32 3, ptr %1, align 4
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3 %append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0 %append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
@@ -286,7 +286,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry unsafe.Slice.next: ; preds = %entry
%5 = trunc nuw i64 %len to i32 %5 = trunc i64 %len to i32
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
@@ -310,7 +310,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry unsafe.Slice.next: ; preds = %entry
%5 = trunc nuw i64 %len to i32 %5 = trunc i64 %len to i32
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
@@ -322,7 +322,7 @@ unsafe.Slice.throw: ; preds = %entry
unreachable unreachable
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+3 -3
View File
@@ -97,7 +97,7 @@ lookup.throw: ; preds = %entry
unreachable unreachable
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+6 -6
View File
@@ -81,7 +81,7 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0 %s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4 store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12 %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 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1 %0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
@@ -109,7 +109,7 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0 %s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4 store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12 %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 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1 %0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
@@ -132,9 +132,9 @@ entry:
ret void ret void
} }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } 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,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind } attributes #5 = { nounwind }
+2 -2
View File
@@ -3,7 +3,7 @@ module github.com/tinygo-org/tinygo
go 1.19 go 1.19
require ( require (
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6 github.com/chromedp/chromedp v0.7.6
@@ -20,7 +20,7 @@ require (
golang.org/x/sys v0.21.0 golang.org/x/sys v0.21.0
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 golang.org/x/tools v0.22.1-0.20240621165957-db513b091504
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9 tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8
) )
require ( require (
+4 -4
View File
@@ -1,5 +1,5 @@
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 h1:cD7QfvrJdYmBw2tFP/VyKPT8ZESlcrwSwo7SvH9Y4dc= github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c h1:4T0Vj1UkGgcpkRrmn7SbokebnlfxJcMZPgWtOYACAAA=
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw= 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 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
@@ -74,5 +74,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9 h1:rMvEzuCYjyiR+pmdiCVWTQw3L6VqiSIXoL19I3lYufE= tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 h1:bLsZXRUBavt++CJlMN7sppNziqu3LyamESLhFJcpqFQ=
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+9 -20
View File
@@ -4,37 +4,29 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"runtime/debug"
"strings" "strings"
) )
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const version = "0.36.0-dev" const version = "0.34.0"
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
GitSha1 string
)
// Return TinyGo version, either in the form 0.30.0 or as a development version // Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012). // (like 0.30.0-dev-abcd012).
func Version() string { func Version() string {
v := version v := version
if strings.HasSuffix(version, "-dev") { if strings.HasSuffix(version, "-dev") && GitSha1 != "" {
if hash := readGitHash(); hash != "" { v += "-" + GitSha1
v += "-" + hash
}
} }
return v return v
} }
func readGitHash() string {
if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
if setting.Key == "vcs.revision" {
return setting.Value[:8]
}
}
}
return ""
}
// GetGorootVersion returns the major and minor version for a given GOROOT path. // GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned. // If the goroot cannot be determined, (0, 0) is returned.
func GetGorootVersion() (major, minor int, err error) { func GetGorootVersion() (major, minor int, err error) {
@@ -50,9 +42,6 @@ func GetGorootVersion() (major, minor int, err error) {
// major, minor, and patch version: 1, 3, and 2 in this example. // major, minor, and patch version: 1, 3, and 2 in this example.
// If there is an error, (0, 0, 0) and an error will be returned. // If there is an error, (0, 0, 0) and an error will be returned.
func Parse(version string) (major, minor, patch int, err error) { func Parse(version string) (major, minor, patch int, err error) {
if strings.HasPrefix(version, "devel ") {
version = strings.Split(strings.TrimPrefix(version, "devel "), version)[0]
}
if version == "" || version[:2] != "go" { if version == "" || version[:2] != "go" {
return 0, 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix") return 0, 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
} }
-1
View File
@@ -21,7 +21,6 @@ func TestParse(t *testing.T) {
{"go1.23.5-rc6", 1, 23, 5, false}, {"go1.23.5-rc6", 1, 23, 5, false},
{"go2.0", 2, 0, 0, false}, {"go2.0", 2, 0, 0, false},
{"go2.0.15", 2, 0, 15, false}, {"go2.0.15", 2, 0, 15, false},
{"devel go1.24-f99f5da18f Thu Nov 14 22:29:26 2024 +0000 darwin/arm64", 1, 24, 0, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.v, func(t *testing.T) { t.Run(tt.v, func(t *testing.T) {
+3 -2
View File
@@ -2,7 +2,7 @@ module github.com/tinygo-org/tinygo/internal/tools
go 1.22.4 go 1.22.4
require github.com/bytecodealliance/wasm-tools-go v0.3.1 require github.com/bytecodealliance/wasm-tools-go v0.3.0
require ( require (
github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect
@@ -12,7 +12,8 @@ require (
github.com/regclient/regclient v0.7.1 // indirect github.com/regclient/regclient v0.7.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-alpha9.2 // 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.21.0 // indirect golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.26.0 // indirect
) )
+8 -6
View File
@@ -1,5 +1,5 @@
github.com/bytecodealliance/wasm-tools-go v0.3.1 h1:9Q9PjSzkbiVmkUvZ7nYCfJ02mcQDBalxycA3s8g7kR4= github.com/bytecodealliance/wasm-tools-go v0.3.0 h1:9aeDFYpbi3gtIW/nJCH+P+LhFMqezGoOfzqbUZLadho=
github.com/bytecodealliance/wasm-tools-go v0.3.1/go.mod h1:vNAQ8DAEp6xvvk+TUHah5DslLEa76f4H6e737OeaxuY= github.com/bytecodealliance/wasm-tools-go v0.3.0/go.mod h1:VY+9FlpLi6jnhCrZLkyJjF9rjU4aEekgaRTk28MS2JE=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= 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/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -23,12 +23,14 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-alpha9.2 h1:CL8llQj3dGRLVQQzHxS+ZYRLanOuhyK1fXgLKD+qV+Y= github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo=
github.com/urfave/cli/v3 v3.0.0-alpha9.2/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= 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=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+3 -12
View File
@@ -287,17 +287,9 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Get the object layout, if it is available. // Get the object layout, if it is available.
llvmLayoutType := r.getLLVMTypeFromLayout(operands[2]) llvmLayoutType := r.getLLVMTypeFromLayout(operands[2])
// Get the alignment of the memory to be allocated.
alignment := 0 // use default alignment if unset
alignAttr := inst.llvmInst.GetCallSiteEnumAttribute(0, llvm.AttributeKindID("align"))
if !alignAttr.IsNil() {
alignment = int(alignAttr.GetEnumValue())
}
// Create the object. // Create the object.
alloc := object{ alloc := object{
globalName: r.pkgName + "$alloc", globalName: r.pkgName + "$alloc",
align: alignment,
llvmLayoutType: llvmLayoutType, llvmLayoutType: llvmLayoutType,
buffer: newRawValue(uint32(size)), buffer: newRawValue(uint32(size)),
size: uint32(size), size: uint32(size),
@@ -654,7 +646,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
globalName: r.pkgName + "$alloca", globalName: r.pkgName + "$alloca",
buffer: newRawValue(uint32(size)), buffer: newRawValue(uint32(size)),
size: uint32(size), size: uint32(size),
align: inst.llvmInst.Alignment(),
} }
index := len(r.objects) index := len(r.objects)
r.objects = append(r.objects, alloca) r.objects = append(r.objects, alloca)
@@ -970,9 +961,9 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
case llvm.Call: case llvm.Call:
llvmFn := operands[len(operands)-1] llvmFn := operands[len(operands)-1]
args := operands[:len(operands)-1] args := operands[:len(operands)-1]
for _, op := range operands { for _, arg := range args {
if op.Type().TypeKind() == llvm.PointerTypeKind { if arg.Type().TypeKind() == llvm.PointerTypeKind {
err := mem.markExternalStore(op) err := mem.markExternalStore(arg)
if err != nil { if err != nil {
return r.errorAt(inst, err) return r.errorAt(inst, err)
} }
+6 -11
View File
@@ -42,7 +42,6 @@ type object struct {
globalName string // name, if not yet created (not guaranteed to be the final name) globalName string // name, if not yet created (not guaranteed to be the final name)
buffer value // buffer with value as given by interp, nil if external buffer value // buffer with value as given by interp, nil if external
size uint32 // must match buffer.len(), if available size uint32 // must match buffer.len(), if available
align int // alignment of the object (may be 0 if unknown)
constant bool // true if this is a constant global constant bool // true if this is a constant global
marked uint8 // 0 means unmarked, 1 means external read, 2 means external write marked uint8 // 0 means unmarked, 1 means external read, 2 means external write
} }
@@ -594,12 +593,6 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
// runtime.alloc. // runtime.alloc.
// First allocate a new global for this object. // First allocate a new global for this object.
obj := mem.get(v.index()) obj := mem.get(v.index())
alignment := obj.align
if alignment == 0 {
// Unknown alignment, perhaps from a direct call to runtime.alloc in
// the runtime. Use a conservative default instead.
alignment = mem.r.maxAlign
}
if obj.llvmType.IsNil() && obj.llvmLayoutType.IsNil() { if obj.llvmType.IsNil() && obj.llvmLayoutType.IsNil() {
// Create an initializer without knowing the global type. // Create an initializer without knowing the global type.
// This is probably the result of a runtime.alloc call. // This is probably the result of a runtime.alloc call.
@@ -610,7 +603,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
globalType := initializer.Type() globalType := initializer.Type()
llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName) llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName)
llvmValue.SetInitializer(initializer) llvmValue.SetInitializer(initializer)
llvmValue.SetAlignment(alignment) llvmValue.SetAlignment(mem.r.maxAlign)
obj.llvmGlobal = llvmValue obj.llvmGlobal = llvmValue
mem.put(v.index(), obj) mem.put(v.index(), obj)
} else { } else {
@@ -649,7 +642,11 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
return llvm.Value{}, errors.New("interp: allocated value does not match allocated type") return llvm.Value{}, errors.New("interp: allocated value does not match allocated type")
} }
llvmValue.SetInitializer(initializer) llvmValue.SetInitializer(initializer)
llvmValue.SetAlignment(alignment) if obj.llvmType.IsNil() {
// The exact type isn't known (only the layout), so use the
// alignment that would normally be expected from runtime.alloc.
llvmValue.SetAlignment(mem.r.maxAlign)
}
} }
// It should be included in r.globals because otherwise markExternal // It should be included in r.globals because otherwise markExternal
@@ -1046,8 +1043,6 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
v.buf[i] = ptrValue.pointer v.buf[i] = ptrValue.pointer
} }
case llvm.ICmp: case llvm.ICmp:
// Note: constant icmp isn't supported anymore in LLVM 19.
// Once we drop support for LLVM 18, this can be removed.
size := r.targetData.TypeAllocSize(llvmValue.Operand(0).Type()) size := r.targetData.TypeAllocSize(llvmValue.Operand(0).Type())
lhs := newRawValue(uint32(size)) lhs := newRawValue(uint32(size))
rhs := newRawValue(uint32(size)) rhs := newRawValue(uint32(size))
+15
View File
@@ -3,6 +3,7 @@ target triple = "x86_64--linux"
@intToPtrResult = global i8 0 @intToPtrResult = global i8 0
@ptrToIntResult = global i8 0 @ptrToIntResult = global i8 0
@icmpResult = global i8 0
@pointerTagResult = global i64 0 @pointerTagResult = global i64 0
@someArray = internal global {i16, i8, i8} zeroinitializer @someArray = internal global {i16, i8, i8} zeroinitializer
@someArrayPointer = global ptr zeroinitializer @someArrayPointer = global ptr zeroinitializer
@@ -16,6 +17,7 @@ define internal void @main.init() {
call void @testIntToPtr() call void @testIntToPtr()
call void @testPtrToInt() call void @testPtrToInt()
call void @testConstGEP() call void @testConstGEP()
call void @testICmp()
call void @testPointerTag() call void @testPointerTag()
ret void ret void
} }
@@ -51,6 +53,19 @@ define internal void @testConstGEP() {
ret void ret void
} }
define internal void @testICmp() {
br i1 icmp eq (i64 ptrtoint (ptr @ptrToIntResult to i64), i64 0), label %equal, label %unequal
equal:
; should not be reached
store i8 1, ptr @icmpResult
ret void
unequal:
; should be reached
store i8 2, ptr @icmpResult
ret void
ret void
}
define internal void @testPointerTag() { define internal void @testPointerTag() {
%val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3 %val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3
store i64 %val, ptr @pointerTagResult store i64 %val, ptr @pointerTagResult
+2 -1
View File
@@ -3,9 +3,10 @@ target triple = "x86_64--linux"
@intToPtrResult = local_unnamed_addr global i8 2 @intToPtrResult = local_unnamed_addr global i8 2
@ptrToIntResult = local_unnamed_addr global i8 2 @ptrToIntResult = local_unnamed_addr global i8 2
@icmpResult = local_unnamed_addr global i8 2
@pointerTagResult = local_unnamed_addr global i64 2 @pointerTagResult = local_unnamed_addr global i64 2
@someArray = internal global { i16, i8, i8 } zeroinitializer @someArray = internal global { i16, i8, i8 } zeroinitializer
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds (i8, ptr @someArray, i64 2) @someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds ({ i16, i8, i8 }, ptr @someArray, i64 0, i32 1)
define void @runtime.initAll() local_unnamed_addr { define void @runtime.initAll() local_unnamed_addr {
ret void ret void
-2
View File
@@ -243,7 +243,6 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"internal/binary/": false, "internal/binary/": false,
"internal/bytealg/": false, "internal/bytealg/": false,
"internal/cm/": false, "internal/cm/": false,
"internal/futex/": false,
"internal/fuzz/": false, "internal/fuzz/": false,
"internal/reflectlite/": false, "internal/reflectlite/": false,
"internal/gclayout": false, "internal/gclayout": false,
@@ -257,7 +256,6 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"runtime/": false, "runtime/": false,
"sync/": true, "sync/": true,
"testing/": true, "testing/": true,
"tinygo/": false,
"unique/": false, "unique/": false,
} }
+1 -1
View File
@@ -485,7 +485,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
var initialCFlags []string var initialCFlags []string
initialCFlags = append(initialCFlags, p.program.config.CFlags(true)...) initialCFlags = append(initialCFlags, p.program.config.CFlags(true)...)
initialCFlags = append(initialCFlags, "-I"+p.Dir) initialCFlags = append(initialCFlags, "-I"+p.Dir)
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.config.GOOS()) generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags)
p.CFlags = append(initialCFlags, cflags...) p.CFlags = append(initialCFlags, cflags...)
p.CGoHeaders = headerCode p.CGoHeaders = headerCode
for path, hash := range accessedFiles { for path, hash := range accessedFiles {
+11 -18
View File
@@ -770,12 +770,11 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
// for the given emulator. // 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) { 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) {
// Determine whether we're on a system that supports environment variables // Determine whether we're on a system that supports environment variables
// and command line parameters (operating systems, WASI) or not (baremetal, // and command line parameters (operating systems, WASI) or not (baremetal).
// WebAssembly in the browser). If we're on a system without an environment, // If we're on a system without an environment, we need to pass command line
// we need to pass command line arguments and environment variables through // arguments and environment variables through global variables (built into
// global variables (built into the binary directly) instead of the // the binary directly) instead of the conventional way.
// conventional way. needsEnvInVars := false
needsEnvInVars := config.GOOS() == "js"
for _, tag := range config.BuildTags() { for _, tag := range config.BuildTags() {
if tag == "baremetal" { if tag == "baremetal" {
needsEnvInVars = true needsEnvInVars = true
@@ -1062,8 +1061,9 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
return points, nil return points, nil
case "windows": case "windows":
// Obtain a list of all currently mounted volumes. // Obtain a list of all currently mounted volumes.
cmd := executeCommand(options, "powershell", "-c", cmd := executeCommand(options, "wmic",
"Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object DeviceID, DriveType, FileSystem, VolumeName") "PATH", "Win32_LogicalDisk",
"get", "DeviceID,VolumeName,FileSystem,DriveType")
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err := cmd.Run() err := cmd.Run()
@@ -1501,14 +1501,14 @@ func main() {
var tags buildutil.TagsFlag var tags buildutil.TagsFlag
flag.Var(&tags, "tags", "a space-separated list of extra build tags") flag.Var(&tags, "tags", "a space-separated list of extra build tags")
target := flag.String("target", "", "chip/board name or JSON target specification file") target := flag.String("target", "", "chip/board name or JSON target specification file")
buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared, wasi-legacy)") buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared)")
var stackSize uint64 var stackSize uint64
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error { flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
size, err := bytesize.Parse(s) size, err := bytesize.Parse(s)
stackSize = uint64(size) stackSize = uint64(size)
return err return err
}) })
printSize := flag.String("size", "", "print sizes (none, short, full, html)") printSize := flag.String("size", "", "print sizes (none, short, full)")
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printCommands := flag.Bool("x", false, "Print commands") printCommands := flag.Bool("x", false, "Print commands")
@@ -1640,19 +1640,12 @@ func main() {
Timeout: *timeout, Timeout: *timeout,
WITPackage: witPackage, WITPackage: witPackage,
WITWorld: witWorld, WITWorld: witWorld,
ExtLDFlags: extLDFlags,
} }
if *printCommands { if *printCommands {
options.PrintCommands = printCommand options.PrintCommands = printCommand
} }
if extLDFlags != "" {
options.ExtLDFlags, err = shlex.Split(extLDFlags)
if err != nil {
fmt.Fprintln(os.Stderr, "could not parse -extldflags:", err)
os.Exit(1)
}
}
err = options.Verify() err = options.Verify()
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err.Error()) fmt.Fprintln(os.Stderr, err.Error())
+3 -83
View File
@@ -15,6 +15,7 @@ import (
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
"slices"
"strings" "strings"
"sync" "sync"
"testing" "testing"
@@ -24,7 +25,6 @@ import (
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
"github.com/tinygo-org/tinygo/builder" "github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics" "github.com/tinygo-org/tinygo/diagnostics"
@@ -429,9 +429,6 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") { for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") {
t.Log(line) t.Log(line)
} }
if stdout.Len() != 0 {
t.Logf("output:\n%s", stdout.String())
}
t.Fail() t.Fail()
return return
} }
@@ -520,7 +517,7 @@ func TestWebAssembly(t *testing.T) {
} }
} }
} }
if !stringSlicesEqual(imports, tc.imports) { if !slices.Equal(imports, tc.imports) {
t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports) t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports)
} }
} }
@@ -528,20 +525,6 @@ func TestWebAssembly(t *testing.T) {
} }
} }
func stringSlicesEqual(s1, s2 []string) bool {
// We can use slices.Equal once we drop support for Go 1.20 (it was added in
// Go 1.21).
if len(s1) != len(s2) {
return false
}
for i, s := range s1 {
if s != s2[i] {
return false
}
}
return true
}
func TestWasmExport(t *testing.T) { func TestWasmExport(t *testing.T) {
t.Parallel() t.Parallel()
@@ -594,15 +577,6 @@ func TestWasmExport(t *testing.T) {
noOutput: true, // wasm-unknown cannot produce output noOutput: true, // wasm-unknown cannot produce output
command: true, command: true,
}, },
// Test buildmode=wasi-legacy with WASI.
{
name: "WASIp1-legacy",
target: "wasip1",
buildMode: "wasi-legacy",
scheduler: "none",
file: "wasmexport-noscheduler.go",
command: true,
},
} }
for _, tc := range tests { for _, tc := range tests {
@@ -709,14 +683,7 @@ func TestWasmExport(t *testing.T) {
if tc.command { if tc.command {
// Call _start (the entry point), which calls // Call _start (the entry point), which calls
// tester.callTestMain, which then runs all the tests. // tester.callTestMain, which then runs all the tests.
_, err := mod.ExportedFunction("_start").Call(ctx) mustCall(mod.ExportedFunction("_start").Call(ctx))
if err != nil {
if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() == 0 {
// Exited with code 0. Nothing to worry about.
} else {
t.Error("failed to run _start:", err)
}
}
} else { } else {
// Run the _initialize call, because this is reactor mode wasm. // Run the _initialize call, because this is reactor mode wasm.
mustCall(mod.ExportedFunction("_initialize").Call(ctx)) mustCall(mod.ExportedFunction("_initialize").Call(ctx))
@@ -761,7 +728,6 @@ func TestWasmFuncOf(t *testing.T) {
// Test //go:wasmexport in JavaScript (using NodeJS). // Test //go:wasmexport in JavaScript (using NodeJS).
func TestWasmExportJS(t *testing.T) { func TestWasmExportJS(t *testing.T) {
t.Parallel()
type testCase struct { type testCase struct {
name string name string
buildMode string buildMode string
@@ -772,9 +738,7 @@ func TestWasmExportJS(t *testing.T) {
{name: "c-shared", buildMode: "c-shared"}, {name: "c-shared", buildMode: "c-shared"},
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Build the wasm binary. // Build the wasm binary.
tmpdir := t.TempDir() tmpdir := t.TempDir()
options := optionsFromTarget("wasm", sema) options := optionsFromTarget("wasm", sema)
@@ -802,56 +766,12 @@ func TestWasmExportJS(t *testing.T) {
} }
} }
// Test whether Go.run() (in wasm_exec.js) normally returns and returns the
// right exit code.
func TestWasmExit(t *testing.T) {
t.Parallel()
type testCase struct {
name string
output string
}
tests := []testCase{
{name: "normal", output: "exit code: 0\n"},
{name: "exit-0", output: "exit code: 0\n"},
{name: "exit-0-sleep", output: "slept\nexit code: 0\n"},
{name: "exit-1", output: "exit code: 1\n"},
{name: "exit-1-sleep", output: "slept\nexit code: 1\n"},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
options := optionsFromTarget("wasm", sema)
buildConfig, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}
buildConfig.Target.Emulator = "node testdata/wasmexit.js {}"
output := &bytes.Buffer{}
_, err = buildAndRun("testdata/wasmexit.go", buildConfig, output, []string{tc.name}, nil, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run()
})
if err != nil {
t.Error(err)
}
expected := "wasmexit test: " + tc.name + "\n" + tc.output
checkOutputData(t, []byte(expected), output.Bytes())
})
}
}
// Check whether the output of a test equals the expected output. // Check whether the output of a test equals the expected output.
func checkOutput(t *testing.T, filename string, actual []byte) { func checkOutput(t *testing.T, filename string, actual []byte) {
expectedOutput, err := os.ReadFile(filename) expectedOutput, err := os.ReadFile(filename)
if err != nil { if err != nil {
t.Fatal("could not read output file:", err) t.Fatal("could not read output file:", err)
} }
checkOutputData(t, expectedOutput, actual)
}
func checkOutputData(t *testing.T, expectedOutput, actual []byte) {
expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n")) expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n"))
actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n")) actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n"))
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey //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 // If you update the above build constraint, you'll probably also need to update
// src/runtime/rand_hwrng.go. // src/runtime/rand_hwrng.go.
-31
View File
@@ -17,37 +17,6 @@ import (
"time" "time"
) )
const (
VersionTLS10 = 0x0301
VersionTLS11 = 0x0302
VersionTLS12 = 0x0303
VersionTLS13 = 0x0304
// Deprecated: SSLv3 is cryptographically broken, and is no longer
// supported by this package. See golang.org/issue/32716.
VersionSSL30 = 0x0300
)
// VersionName returns the name for the provided TLS version number
// (e.g. "TLS 1.3"), or a fallback representation of the value if the
// version is not implemented by this package.
func VersionName(version uint16) string {
switch version {
case VersionSSL30:
return "SSLv3"
case VersionTLS10:
return "TLS 1.0"
case VersionTLS11:
return "TLS 1.1"
case VersionTLS12:
return "TLS 1.2"
case VersionTLS13:
return "TLS 1.3"
default:
return fmt.Sprintf("0x%04X", version)
}
}
// CurveID is the type of a TLS identifier for an elliptic curve. See // 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. // https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
// //
+1 -7
View File
@@ -101,13 +101,7 @@ type Dialer struct {
// //
// The returned Conn, if any, will always be of type *Conn. // The returned Conn, if any, will always be of type *Conn.
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
switch network { return nil, errors.New("tls:DialContext not implemented")
case "tcp", "tcp4":
default:
return nil, fmt.Errorf("Network %s not supported", network)
}
return net.DialTLS(addr)
} }
// LoadX509KeyPair reads and parses a public/private key pair from a pair // LoadX509KeyPair reads and parses a public/private key pair from a pair
-139
View File
@@ -1,139 +0,0 @@
//go:build tkey
// Hand written file based on https://github.com/tillitis/tkey-libs/blob/main/include/tkey/tk1_mem.h
package tkey
import (
"runtime/volatile"
"unsafe"
)
// Peripherals
var (
TRNG = (*TRNG_Type)(unsafe.Pointer(TK1_MMIO_TRNG_BASE))
TIMER = (*TIMER_Type)(unsafe.Pointer(TK1_MMIO_TIMER_BASE))
UDS = (*UDS_Type)(unsafe.Pointer(TK1_MMIO_UDS_BASE))
UART = (*UART_Type)(unsafe.Pointer(TK1_MMIO_UART_BASE))
TOUCH = (*TOUCH_Type)(unsafe.Pointer(TK1_MMIO_TOUCH_BASE))
TK1 = (*TK1_Type)(unsafe.Pointer(TK1_MMIO_TK1_BASE))
)
// Memory sections
const (
TK1_ROM_BASE uintptr = 0x00000000
TK1_RAM_BASE uintptr = 0x40000000
TK1_MMIO_BASE uintptr = 0xc0000000
TK1_MMIO_TRNG_BASE uintptr = 0xc0000000
TK1_MMIO_TIMER_BASE uintptr = 0xc1000000
TK1_MMIO_UDS_BASE uintptr = 0xc2000000
TK1_MMIO_UART_BASE uintptr = 0xc3000000
TK1_MMIO_TOUCH_BASE uintptr = 0xc4000000
TK1_MMIO_FW_RAM_BASE uintptr = 0xd0000000
TK1_MMIO_TK1_BASE uintptr = 0xff000000
)
// Memory section sizes
const (
TK1_RAM_SIZE uintptr = 0x20000
TK1_MMIO_SIZE uintptr = 0x3fffffff
)
type TRNG_Type struct {
_ [36]byte
STATUS volatile.Register32
_ [88]byte
ENTROPY volatile.Register32
}
type TIMER_Type struct {
_ [32]byte
CTRL volatile.Register32
STATUS volatile.Register32
PRESCALER volatile.Register32
TIMER volatile.Register32
}
type UDS_Type struct {
_ [64]byte
DATA [8]volatile.Register32
}
type UART_Type struct {
_ [128]byte
RX_STATUS volatile.Register32
RX_DATA volatile.Register32
RX_BYTES volatile.Register32
_ [116]byte
TX_STATUS volatile.Register32
TX_DATA volatile.Register32
}
type TOUCH_Type struct {
_ [36]byte
STATUS volatile.Register32
}
type TK1_Type struct {
NAME0 volatile.Register32
NAME1 volatile.Register32
VERSION volatile.Register32
_ [16]byte
SWITCH_APP volatile.Register32
_ [4]byte
LED volatile.Register32
GPIO volatile.Register16
APP_ADDR volatile.Register32
APP_SIZE volatile.Register32
BLAKE2S volatile.Register32
_ [72]byte
CDI_FIRST [8]volatile.Register32
_ [32]byte
UDI_FIRST [2]volatile.Register32
_ [62]byte
RAM_ADDR_RAND volatile.Register16
_ [2]byte
RAM_DATA_RAND volatile.Register16
_ [126]byte
CPU_MON_CTRL volatile.Register16
_ [2]byte
CPU_MON_FIRST volatile.Register32
CPU_MON_LAST volatile.Register32
_ [60]byte
SYSTEM_RESET volatile.Register16
_ [66]byte
SPI_EN volatile.Register32
SPI_XFER volatile.Register32
SPI_DATA volatile.Register32
}
const (
TK1_MMIO_TIMER_CTRL_START_BIT = 0
TK1_MMIO_TIMER_CTRL_STOP_BIT = 1
TK1_MMIO_TIMER_CTRL_START = 1 << TK1_MMIO_TIMER_CTRL_START_BIT
TK1_MMIO_TIMER_CTRL_STOP = 1 << TK1_MMIO_TIMER_CTRL_STOP_BIT
TK1_MMIO_TK1_LED_R_BIT = 2
TK1_MMIO_TK1_LED_G_BIT = 1
TK1_MMIO_TK1_LED_B_BIT = 0
TK1_MMIO_TK1_GPIO1_BIT = 0
TK1_MMIO_TK1_GPIO2_BIT = 1
TK1_MMIO_TK1_GPIO3_BIT = 2
TK1_MMIO_TK1_GPIO4_BIT = 3
)
+4 -2
View File
@@ -7,13 +7,15 @@ import (
"time" "time"
) )
// change these to test a different UART or pins if available
var ( var (
uart = machine.Serial uart = machine.Serial
tx = machine.UART_TX_PIN
rx = machine.UART_RX_PIN
) )
func main() { func main() {
// use default settings for UART uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
uart.Configure(machine.UARTConfig{})
uart.Write([]byte("Echo console enabled. Type something then press enter:\r\n")) uart.Write([]byte("Echo console enabled. Type something then press enter:\r\n"))
input := make([]byte, 64) input := make([]byte, 64)
+2 -2
View File
@@ -13,11 +13,11 @@ func main() {
Stereo: true, Stereo: true,
}) })
data := make([]uint16, 64) data := make([]uint32, 64)
for { for {
// get the next group of samples // get the next group of samples
machine.I2S0.ReadMono(data) machine.I2S0.Read(data)
println("data", data[0], data[1], data[2], data[4], "...") println("data", data[0], data[1], data[2], data[4], "...")
} }
+1 -10
View File
@@ -3,7 +3,7 @@ package main
// This example demonstrates how to use pin change interrupts. // This example demonstrates how to use pin change interrupts.
// //
// This is only an example and should not be copied directly in any serious // This is only an example and should not be copied directly in any serious
// circuit, because it only naively implements an important feature: debouncing. // circuit, because it lacks an important feature: debouncing.
// See: https://en.wikipedia.org/wiki/Switch#Contact_bounce // See: https://en.wikipedia.org/wiki/Switch#Contact_bounce
import ( import (
@@ -15,8 +15,6 @@ const (
led = machine.LED led = machine.LED
) )
var lastPress time.Time
func main() { func main() {
// Configure the LED, defaulting to on (usually setting the pin to low will // Configure the LED, defaulting to on (usually setting the pin to low will
@@ -31,13 +29,6 @@ func main() {
// Set an interrupt on this pin. // Set an interrupt on this pin.
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) { err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
// Ignore events that are too close to the last registered press (debouncing)
if time.Since(lastPress) < 100*time.Millisecond {
return
}
lastPress = time.Now()
led.Set(!led.Get()) led.Set(!led.Get())
}) })
if err != nil { if err != nil {
-7
View File
@@ -1,7 +0,0 @@
package abi
type Type struct {
// Intentionally left empty. TinyGo uses a different way to represent types,
// so this is unimplementable. The type definition here is purely for
// compatibility.
}
-10
View File
@@ -71,16 +71,6 @@ func (r *result[Shape, OK, Err]) Err() *Err {
return (*Err)(unsafe.Pointer(&r.data)) return (*Err)(unsafe.Pointer(&r.data))
} }
// Result returns (OK, zero value of Err, false) if r represents the OK case,
// or (zero value of OK, Err, true) if r represents the error case.
// This does not have a pointer receiver, so it can be chained.
func (r result[Shape, OK, Err]) Result() (ok OK, err Err, isErr bool) {
if r.isErr {
return ok, *(*Err)(unsafe.Pointer(&r.data)), true
}
return *(*OK)(unsafe.Pointer(&r.data)), err, false
}
// This function is sized so it can be inlined and optimized away. // This function is sized so it can be inlined and optimized away.
func (r *result[Shape, OK, Err]) validate() { func (r *result[Shape, OK, Err]) validate() {
var shape Shape var shape Shape
-72
View File
@@ -1,72 +0,0 @@
package futex
// Cross platform futex implementation.
// Futexes are supported on all major operating systems and on WebAssembly.
//
// For more information, see: https://outerproduct.net/futex-dictionary.html
import (
"sync/atomic"
"unsafe"
)
// A futex is a way for userspace to wait with the pointer as the key, and for
// another thread to wake one or all waiting threads keyed on the same pointer.
//
// A futex does not change the underlying value, it only reads it before going
// to sleep (atomically) to prevent lost wake-ups.
type Futex struct {
atomic.Uint32
}
// Atomically check for cmp to still be equal to the futex value and if so, go
// to sleep. Return true if we were definitely awoken by a call to Wake or
// WakeAll, and false if we can't be sure of that.
func (f *Futex) Wait(cmp uint32) bool {
tinygo_futex_wait((*uint32)(unsafe.Pointer(&f.Uint32)), cmp)
// We *could* detect a zero return value from the futex system call which
// would indicate we got awoken by a Wake or WakeAll call. However, this is
// what the manual page has to say:
//
// > Note that a wake-up can also be caused by common futex usage patterns
// > in unrelated code that happened to have previously used the futex
// > word's memory location (e.g., typical futex-based implementations of
// > Pthreads mutexes can cause this under some conditions). Therefore,
// > callers should always conservatively assume that a return value of 0
// > can mean a spurious wake-up, and use the futex word's value (i.e., the
// > user-space synchronization scheme) to decide whether to continue to
// > block or not.
//
// I'm not sure whether we do anything like pthread does, so to be on the
// safe side we say we don't know whether the wakeup was spurious or not and
// return false.
return false
}
// Like Wait, but times out after the number of nanoseconds in timeout.
func (f *Futex) WaitUntil(cmp uint32, timeout uint64) {
tinygo_futex_wait_timeout((*uint32)(unsafe.Pointer(&f.Uint32)), cmp, timeout)
}
// Wake a single waiter.
func (f *Futex) Wake() {
tinygo_futex_wake((*uint32)(unsafe.Pointer(&f.Uint32)))
}
// Wake all waiters.
func (f *Futex) WakeAll() {
tinygo_futex_wake_all((*uint32)(unsafe.Pointer(&f.Uint32)))
}
//export tinygo_futex_wait
func tinygo_futex_wait(addr *uint32, cmp uint32)
//export tinygo_futex_wait_timeout
func tinygo_futex_wait_timeout(addr *uint32, cmp uint32, timeout uint64)
//export tinygo_futex_wake
func tinygo_futex_wake(addr *uint32)
//export tinygo_futex_wake_all
func tinygo_futex_wake_all(addr *uint32)
-49
View File
@@ -1,49 +0,0 @@
//go:build none
// This file is manually included, to avoid CGo which would cause a circular
// import.
#include <stdint.h>
// This API isn't documented by Apple, but it is used by LLVM libc++ (so should
// be stable) and has been documented extensively here:
// https://outerproduct.net/futex-dictionary.html
int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout_us);
int __ulock_wait2(uint32_t operation, void *addr, uint64_t value, uint64_t timeout_ns, uint64_t value2);
int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
// Operation code.
#define UL_COMPARE_AND_WAIT 1
// Flags to the operation value.
#define ULF_WAKE_ALL 0x00000100
#define ULF_NO_ERRNO 0x01000000
void tinygo_futex_wait(uint32_t *addr, uint32_t cmp) {
__ulock_wait(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, 0);
}
void tinygo_futex_wait_timeout(uint32_t *addr, uint32_t cmp, uint64_t timeout) {
// Make sure that an accidental use of a zero timeout is not treated as an
// infinite timeout. Return if it's zero since it wouldn't be waiting for
// any significant time anyway.
// Probably unnecessary, but guards against potential bugs.
if (timeout == 0) {
return;
}
// Note: __ulock_wait2 is available since MacOS 11.
// I think that's fine, since the version before that (MacOS 10.15) is EOL
// since 2022. Though if needed, we could certainly use __ulock_wait instead
// and deal with the smaller timeout value.
__ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, timeout, 0);
}
void tinygo_futex_wake(uint32_t *addr) {
__ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, 0);
}
void tinygo_futex_wake_all(uint32_t *addr) {
__ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO|ULF_WAKE_ALL, addr, 0);
}
-33
View File
@@ -1,33 +0,0 @@
//go:build none
// This file is manually included, to avoid CGo which would cause a circular
// import.
#include <limits.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_PRIVATE_FLAG 128
void tinygo_futex_wait(uint32_t *addr, uint32_t cmp) {
syscall(SYS_futex, addr, FUTEX_WAIT|FUTEX_PRIVATE_FLAG, cmp, NULL, NULL, 0);
}
void tinygo_futex_wait_timeout(uint32_t *addr, uint32_t cmp, uint64_t timeout) {
struct timespec ts = {0};
ts.tv_sec = timeout / 1000000000;
ts.tv_nsec = timeout % 1000000000;
syscall(SYS_futex, addr, FUTEX_WAIT|FUTEX_PRIVATE_FLAG, cmp, &ts, NULL, 0);
}
void tinygo_futex_wake(uint32_t *addr) {
syscall(SYS_futex, addr, FUTEX_WAKE|FUTEX_PRIVATE_FLAG, 1, NULL, NULL, 0);
}
void tinygo_futex_wake_all(uint32_t *addr) {
syscall(SYS_futex, addr, FUTEX_WAKE|FUTEX_PRIVATE_FLAG, INT_MAX, NULL, NULL, 0);
}

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