Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem e0bdf2b070 WIP x509 on macOS 2025-08-04 14:27:20 +02:00
443 changed files with 5721 additions and 23908 deletions
+117
View File
@@ -0,0 +1,117 @@
version: 2.1
commands:
submodules:
steps:
- run:
name: "Pull submodules"
command: git submodule update --init
llvm-source-linux:
steps:
- restore_cache:
keys:
- llvm-source-19-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-19-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/compiler-rt
- llvm-project/lld/include
- llvm-project/llvm/include
hack-ninja-jobs:
steps:
- run:
name: "Hack Ninja to use less jobs"
command: |
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
chmod +x /go/bin/ninja
build-binaryen-linux:
steps:
- restore_cache:
keys:
- binaryen-linux-v3
- run:
name: "Build Binaryen"
command: |
make binaryen
- save_cache:
key: binaryen-linux-v3
paths:
- build/wasm-opt
test-linux:
parameters:
llvm:
type: string
fmt-check:
type: boolean
default: true
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
echo 'deb https://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update
apt-get install --no-install-recommends -y \
llvm-<<parameters.llvm>>-dev \
clang-<<parameters.llvm>> \
libclang-<<parameters.llvm>>-dev \
lld-<<parameters.llvm>> \
cmake \
ninja-build
- hack-ninja-jobs
- build-binaryen-linux
- restore_cache:
keys:
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v4-{{ checksum "go.mod" }}
- llvm-source-linux
- run: go install -tags=llvm<<parameters.llvm>> .
- when:
condition: <<parameters.fmt-check>>
steps:
- run:
# Do this before gen-device so that it doesn't check the
# formatting of generated files.
name: Check Go code formatting
command: make fmt-check lint
- 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
- save_cache:
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
jobs:
test-llvm15-go122:
docker:
- image: golang:1.22-bullseye
steps:
- test-linux:
llvm: "15"
resource_class: large
test-llvm20-go124:
docker:
- image: golang:1.24-bullseye
steps:
- test-linux:
llvm: "20"
resource_class: large
workflows:
test-all:
jobs:
# This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass.
- test-llvm15-go122
# This tests LLVM 20 support when linking against system libraries.
- test-llvm20-go124
+1
View File
@@ -1,4 +1,5 @@
build/
llvm-*/
.github
.circleci
+26 -23
View File
@@ -16,37 +16,36 @@ jobs:
name: build-macos
strategy:
matrix:
# macos-14: arm64 (oldest supported version as of 18-11-2025)
# macos-15-intel: amd64 (last intel version to be supported by github runners)
# See https://github.com/actions/runner-images/issues/13046
os: [macos-14, macos-15-intel]
# macos-13: amd64 (oldest supported version as of 18-10-2024)
# macos-14: arm64 (oldest arm64 version)
os: [macos-13, macos-14]
include:
- os: macos-13
goarch: amd64
- os: macos-14
goarch: arm64
- os: macos-15-intel
goarch: amd64
runs-on: ${{ matrix.os }}
steps:
- name: Install Dependencies
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-${{ matrix.os }}-v1
key: llvm-source-19-${{ matrix.os }}-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -57,7 +56,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -68,10 +67,10 @@ jobs:
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-20-${{ matrix.os }}-v2
key: llvm-build-19-${{ matrix.os }}-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -80,12 +79,12 @@ jobs:
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install ninja
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
@@ -101,11 +100,16 @@ jobs:
- name: Make release artifact
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact
uses: actions/upload-artifact@v7
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a double-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with:
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
archive: false
- name: Smoke tests
run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew:
@@ -116,7 +120,7 @@ jobs:
version: [16, 17, 18, 19, 20]
steps:
- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@main
uses: Homebrew/actions/setup-homebrew@master
- name: Fix Python symlinks
run: |
# Github runners have broken symlinks, so relink
@@ -125,13 +129,12 @@ jobs:
- name: Install LLVM
run: |
brew install llvm@${{ matrix.version }}
brew link llvm@${{ matrix.version }}
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }}
+48 -6
View File
@@ -31,14 +31,14 @@ jobs:
sudo rm -rf /usr/local/share/boost
df -h
- name: Check out the repo
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: |
tinygo/tinygo-dev
@@ -47,18 +47,18 @@ jobs:
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v7
uses: docker/build-push-action@v5
with:
context: .
push: true
@@ -66,3 +66,45 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger Bluetooth repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFS repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFont repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyDraw repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyTerm repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
+56 -66
View File
@@ -18,37 +18,37 @@ jobs:
# statically linked binary.
runs-on: ubuntu-latest
container:
image: golang:1.26-alpine
image: golang:1.24-alpine
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Install apk dependencies
# tar: needed for actions/cache@v5
# tar: needed for actions/cache@v4
# git+openssh: needed for checkout (I think?)
# ruby: needed to install fpm
run: apk add tar git openssh make g++ ruby-dev mold
run: apk add tar git openssh make g++ ruby-dev
- name: Work around CVE-2022-24765
# We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Cache Go
uses: actions/cache@v5
uses: actions/cache@v4
with:
key: go-cache-linux-alpine-v2-${{ hashFiles('go.mod') }}
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-linux-alpine-v2
key: llvm-source-19-linux-alpine-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -59,7 +59,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -70,10 +70,10 @@ jobs:
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-20-linux-alpine-v2
key: llvm-build-19-linux-alpine-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -88,16 +88,16 @@ jobs:
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v5
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-alpine-v2
key: binaryen-linux-alpine-v1
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
@@ -118,31 +118,26 @@ jobs:
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.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
- name: "Publish release artifact: tarball"
uses: actions/upload-artifact@v7
- name: Publish release artifact
uses: actions/upload-artifact@v4
with:
name: tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
path: /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
archive: false
- name: "Publish release artifact: Debian package"
uses: actions/upload-artifact@v7
with:
name: tinygo_${{ steps.version.outputs.version }}_amd64.deb
path: /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
archive: false
name: linux-amd64-double-zipped-${{ steps.version.outputs.version }}
path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -151,9 +146,9 @@ jobs:
- name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Download release artifact
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
- name: Extract release tarball
run: |
mkdir -p ~/lib
@@ -169,7 +164,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Install apt dependencies
@@ -184,12 +179,12 @@ jobs:
simavr \
ninja-build
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Install Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install wasmtime
@@ -199,10 +194,10 @@ jobs:
- name: Setup `wasm-tools`
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-linux-asserts-v1
key: llvm-source-19-linux-asserts-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -213,7 +208,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -224,10 +219,10 @@ jobs:
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-20-linux-asserts-v1
key: llvm-build-19-linux-asserts-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -240,13 +235,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v5
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-asserts-v1
@@ -289,7 +284,7 @@ jobs:
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Get TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
@@ -301,15 +296,15 @@ jobs:
g++-${{ matrix.toolchain }} \
libc6-dev-${{ matrix.libc }}-cross
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-linux-v1
key: llvm-source-19-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -320,7 +315,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -331,10 +326,10 @@ jobs:
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-20-linux-${{ matrix.goarch }}-v1
key: llvm-build-19-linux-${{ matrix.goarch }}-v3
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -349,13 +344,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v5
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-${{ matrix.goarch }}-v4
@@ -375,9 +370,9 @@ jobs:
run: |
make CROSS=${{ matrix.toolchain }}
- name: Download amd64 release
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
- name: Extract amd64 release
run: |
mkdir -p build/release
@@ -389,17 +384,12 @@ jobs:
- name: Create ${{ matrix.goarch }} release
run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
- name: "Publish release artifact: tarball"
uses: actions/upload-artifact@v7
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
- name: Publish release artifact
uses: actions/upload-artifact@v4
with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
path: /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
archive: false
- name: "Publish release artifact: Debian package"
uses: actions/upload-artifact@v7
with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
path: /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
archive: false
name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
+7 -7
View File
@@ -25,18 +25,18 @@ jobs:
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: |
tinygo/llvm-20
ghcr.io/${{ github.repository_owner }}/llvm-20
tinygo/llvm-19
ghcr.io/${{ github.repository_owner }}/llvm-19
tags: |
type=sha,format=long
type=raw,value=latest
@@ -46,13 +46,13 @@ jobs:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v7
uses: docker/build-push-action@v5
with:
target: tinygo-llvm-build
context: .
+5 -5
View File
@@ -21,28 +21,28 @@ jobs:
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
run: sudo apt-get remove llvm-18
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Pull musl, bdwgc
run: |
git submodule update --init lib/musl lib/bdwgc
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-linux-nix-v1
key: llvm-source-19-linux-nix-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/compiler-rt
- uses: cachix/install-nix-action@v31
- uses: cachix/install-nix-action@v22
- name: Test
run: |
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
+4 -4
View File
@@ -20,24 +20,24 @@ jobs:
run: |
echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch all history (no sparse checkout)
submodules: true
- name: Install apt dependencies
run: ./.github/workflows/sizediff-install-pkgs.sh
- name: Restore LLVM source cache
uses: actions/cache@v5
uses: actions/cache@v4
id: cache-llvm-source
with:
key: llvm-source-20-sizediff-v1
key: llvm-source-19-sizediff-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache Go
uses: actions/cache@v5
uses: actions/cache@v4
with:
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
path: |
+53 -37
View File
@@ -24,13 +24,14 @@ jobs:
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop config use_external_7zip true
scoop install ninja binaryen
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Extract TinyGo version
@@ -38,15 +39,15 @@ jobs:
shell: bash
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Restore cached LLVM source
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-20-windows-v1
key: llvm-source-19-windows-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -57,7 +58,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save cached LLVM source
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -68,10 +69,10 @@ jobs:
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore cached LLVM build
uses: actions/cache/restore@v5
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-20-windows-v2
key: llvm-build-19-windows-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -85,21 +86,20 @@ jobs:
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save cached LLVM build
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Go cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
key: go-cache-windows-v2-${{ hashFiles('go.mod') }}
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
run: |
scoop config use_external_7zip true
scoop install wasmtime@29.0.1
- name: make gen-device
run: make -j3 gen-device
@@ -114,11 +114,16 @@ jobs:
working-directory: build/release
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo
- name: Publish release artifact
uses: actions/upload-artifact@v7
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a dobule-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with:
name: tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
name: windows-amd64-double-zipped-${{ steps.version.outputs.version }}
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
archive: false
smoke-test-windows:
runs-on: windows-2022
@@ -131,24 +136,28 @@ jobs:
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop config use_external_7zip true
scoop install binaryen
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/
# This build is already unzipped.
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -164,18 +173,21 @@ jobs:
maximum-size: 24GB
disk-root: "C:"
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/
# This build is already unzipped.
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -190,23 +202,27 @@ jobs:
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop config use_external_7zip true
scoop install binaryen wasmtime@29.0.1
scoop install binaryen && scoop install wasmtime@29.0.1
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
go-version: '1.24'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/
# This build is already unzipped.
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
+2 -2
View File
@@ -16,13 +16,13 @@
url = https://github.com/WebAssembly/wasi-libc
[submodule "lib/picolibc"]
path = lib/picolibc
url = https://github.com/picolibc/picolibc.git
url = https://github.com/keith-packard/picolibc.git
[submodule "lib/stm32-svd"]
path = lib/stm32-svd
url = https://github.com/tinygo-org/stm32-svd
[submodule "lib/musl"]
path = lib/musl
url = https://github.com/tinygo-org/musl-libc.git
url = git://git.musl-libc.org/musl
[submodule "lib/binaryen"]
path = lib/binaryen
url = https://github.com/WebAssembly/binaryen.git
-310
View File
@@ -1,313 +1,3 @@
0.41.1
---
* **machine**
- esp32c3: correct pin interrupt setup call that was overlooked from #5320
* **runtime**
- esp32s3: wait for TIMG0 update register to clear before reading timer registers
* **net**
- update net module to a version that is backwards compatible with Go 1.25.x to fix #5332
0.41.0
---
* **general**
- go.mod, compiler: bump minimum Go version to 1.23
- builder: support Go 1.26 now
- feat: add inheritable-only field to filter processor-level targets (#5270)
- feature: add esp32flash flash method for esp32s3/esp32c3/esp32/esp8266
- flashing: introduce flash method 'esp32jtag' for esp32c3/esp32s3 targets
- fashing: add "adb" flash method using Android Debug Bridge
- main: auto-use best available flashing options on esp32
- espflasher: update to espflasher 0.6.0
* **compiler**
- implement method-set based AssignableTo and Implements (#5304)
- simplify createObjectLayout
- implement copy directly
- fix min/max on floats by using intrinsics
- add element layout to sliceAppend
- add intrinsic for crypto/internal/constanttime.boolToUint8
- fix SyscallN handling for Windows on Go 1.26+
* **core**
- reflect: add TypeAssert
- reflect: fix TypeAssert for structs
- sync: add WaitGroup.Go
- os: add UserCacheDir and UserConfigDir
- os: implement Lchown function for changing file ownership (#5161)
- testing: add b.ReportMetric()
- errors: add errors package to passing list
- internal/gclayout: use correct lengths
- internal/abi: add EscapeNonString, EscapeToResultNonString
- internal, runtime: add internal fips bool
- internal/itoa: resurrect from Go stdlib
- internal/syscall/unix: implement GetRandom for WASI targets
- interp: make ptrtoint size mismatch a recoverable error
- loader: support "all:" prefix in //go:embed patterns
- loader, crypto/internal/entropy: fix 32 MiB RAM overflow on microcontrollers
- loader, unicode/utf8: fix hiBits overflow on 16-bit AVR targets
- builder: order embedded files deterministically
- builder: fix panic in findPackagePath when using -size short
- builder: fix SIGSEGV when stripping duplicate function definitions
- builder, runtime: fix duplicate symbol error with Go 1.26+ on Windows
- builder: use target-specific -march for RISC-V library compilation
- transform: modify output format from the -print-allocs flag to match the go coverage tool format
- cgo: allow for changes to 'short-enums' flag
- wasm: add more stubbed file operations
* **machine**
- esp32c3: implement BlockDevice for esp32c3 flash
- esp32c3: clear GPIO STATUS before dispatching pin callbacks
- esp32c3: implement USBDevice using interrupts
- esp32c3: add Enable stub for QEMU test target
- esp32c3: fix interrupt disable handling
- esp32c3: clear MCAUSE after handling interrupt
- esp32c3: map missing IRAM sections in linker script
- esp32c3: fix to use PROVIDE() for WiFi/BLE ROM function addresses to allow blob overrides
- esp32c3: add WiFi/BLE ROM linker support
- esp32c3: use TIMG0 alarm interrupt for sleepTicks instead of busy-waiting
- esp32s3: implement Pin.SetInterrupt for GPIO pin change interrupts
- esp32s3: use edge-triggered CPU interrupt for GPIO pin interrupts
- esp32s3: add interrupt support (#5244)
- esp32s3: switch USB implementation to use interrupts instead of polling
- esp32s3: replace inline ISR with full interrupt vector handler
- esp32s3: use TIMG0 alarm interrupt for sleepTicks
- esp32s3: improve exception handlers, add procPin/procUnpin, and linker wrap flags
- esp32s3: fix Xtensa register window spill using recursive call4 in task switching
- esp32s3: update linker script and boot assembly for multi-page flash XIP mapping
- esp32s3: add flash XIP boot assembly with cache/MMU init
- esp32s3: implement SPI (#5169)
- esp32s3: implement I2C interface (#5210)
- esp32s3: implement RNG based on onboard hardware random number generator
- esp32s3,esp32c3: add USB serial support
- esp32s3,esp32c3: add txStalled flag to skip USB serial spin when no host
- esp32s3,esp32c3: make USB Serial/JTAG writes non-blocking when FIFO is full
- esp32c3/esp32s3: refactor ADC implementation to reduce code duplication
- esp32s3,esp32c3: add ADC support (#5231)
- esp32s3,esp32c3: add PWM support (#5215)
- esp32c3/esp32s3: refactoring and corrections for SPI implementation
- esp32xx: add WASM simulator support for ESP32-C3/ESP32-S3 targets
- esp32: default SPI CS pin to NoPin when unset
- esp: fix tinygo_scanCurrentStack to spill register windows
- stm32: fix UART interrupt storm caused by uncleared overrun error
- stm32: fix PWM problem due to register shifting
- stm32: add STM32U585 target definition and runtime
- stm32: add STM32U5 GPIO, pin interrupts, and UART support
- stm32: add STM32U5 I2C support
- stm32: add STM32U5 SPI support
- stm32u585: implement ADC
- stm32g0b1: add support (#5150)
- stm32g0b1: add Watchdog + ADC support (#5158)
- stm32l0: add flash support
- stm32l0x1,l0x2: TIM: adapt to 32-bit register access
- stm32g0: sync with updated stm32 device files
- attiny85: add USI-based SPI support (#5181)
- attiny85: add PWM support (#5171)
- rp: add Close function to UART to allow for removing all system resources/power usage
- rp: use blockReset() and unresetBlockWait() helper functions for peripheral reset/unreset
- rp2: prevent PWM Period method overflow
- rp2: add per-byte timeout budget for I2C (#5189)
- feather-m0: export UART0 and pins
- usb/cdc: better ring buffer implementation (#5209)
- fix: replace ! with ~ for register mask
- atmega328p_simulator: add correct build tag for arduino_uno after renaming
* **net**
- update to Go 1.26.2 net package with UDP and JS improvements
* **runtime**
- implement fminimum/fmaximum
- make timeoffset atomic
- add MemStats.HeapObjects
- handle GODEBUG on wasip2 (#5312)
- fix Darwin syscall return value truncation and lost arguments
- add syscall.runtimeClearenv for Go 1.26
- split syscall functions for darwin changes for 1.26
- fix: init heap before random number seed on wasm platforms
* **targets**
- add esp32s3-supermini board target
- add support for Seeedstudio Xiao-RP2350 board
- add Shrike Lite board (#5170)
- rename arduino target to arduino-uno
- add pins/setup for Arduino UNO Q board QWIIC connector
- correct pin mapping for Arduino UNO Q STM32 MCU
- add stm32u585 openocd commands for flashing on Arduino UNO Q
- correct name/tag use for esp32s3-wroom1 board
- modify esp32, esp32s3, esp32c3, & esp8266 targets to use built-in esp32flash
- switch rp2040/rp2350 to default to tasks scheduler
- change default stack size for esp32c3 and esp32s3 to 8196
- swan: rename group build tag stm32l4x5 => stm32l4y5 to avoid clash with stm32 device name
- nucleo-f722ze: add build-tag stm32f722
- fix: set stm32u5x clock rate to default
- create generic targets for esp32 boards
* **libs**
- stm32-svd: update submodule
- update tools/gen-device-svd for recent changes to stm32-svd file structure (#5212)
* **build/test**
- build: use Golang 1.26 for all builds
- build: actually use the version of llvm we are supposed to be testing by using brew link command
- build: let scoop run updates to resolve binaryen install failures on Windows
- ci: don't double zip release artifacts
- test: increase default timeout from 1 to 2 minutes to prevent spurious CI fails
- testdata: fix flaky timers test by draining ticker channel after Stop
- testdata: more corpus entries (#5182)
- add soypat/lneto to corpus
- GNUmakefile: add context and expvar to stdlib tests
- GNUmakefile: add encoding/xml to stdlib tests on Linux
- main (test): skip mipsle test if the emulator is missing
- make: remove machine without board from smoketest
- stm32: add Arduino UNO Q to smoketests
- flake: bump to nixpkgs 25.11
- chore: update all github actions to latest versions
- fix: use external 7zip for scoop installs on Windows
0.40.1
---
* **machine**
- nrf: fix flash writes when SoftDevice is enabled
* **runtime**
- runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
- runtime: add calls to initRand() during run() for all schedulers
- runtime: call initRand() before initHeap() during initialization
- runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
* **libs**
- picolibc: use updated location for git repo
0.40.0
---
* **general**
- all: add full LLVM 20 support
- core: feat: enable //go:linkname pragma for globals
- core: feature: Add flag to ignore go compatibility matrix (#5078)
- chore: update version for 0.40 development cycle
* **compiler**
- emit an error when the actual arch doesn't match GOARCH
- mark string parameters as readonly
- use Tarjan's SCC algorithm to detect loops for defer
- lower "large stack" limit to 16kb
* **core**
- shrink bdwgc library
- Fix linker errors for runtime.vgetrandom and crypto/internal/sysrand.fatal
- fix: add TryLock to sync.RWMutex
- fix: correct linter issues exposed by the fix in #4679
- fix: don't hardcode success return state
- fix: expand RTT debugger compatibility
- internal/task (threads): save stack bounds instead of scanning under a lock
- internal/task: create detached threads and fix error handling
- interp: better errors when debugging interp
- transform (gc): create stack slots in callers of external functions
- internal/task: prevent semaphore resource leak for threads scheduler
* **machine**
- cortexm: optimize code size for the HardFault_Handler
- fe310: add I2C pins for the HiFive1b
- clarify WriteAt semantics of BlockDevice
- fix deprecated AsmFull comment (#5005)
- make sure DMA buffers do not escape unnecessarily
- only enable USB-CDC when needed
- use larger SPI MAXCNT on nrf52833 and nrf52840
- fix: update m.queuedBytes when clamping output to avoid corrupting sentBytes
- fix: use int64 in ReadTemperature to avoid overflow
- fix(rp2): disable DBGPAUSE on startup
- fix(rp2): possible integer overflow while computing factors for SPI baudrate
- fix(rp2): reset spinlocks at startup
- fix(rp2): switch spinlock busy loop to wfe
- fix(rp2): use side-effect-free spinlocks
- nrf: add ADC_VDDH which is an ADC pin for VDDH
- nrf: don't block SPI transfer
- nrf: don't set PSELN, it's ignored in single ended mode anyway
- nrf: fix typo in ADC configuration
- nrf: refactor SoftDevice enabled check
- nrf: rename pwmPin to adcPin
- nrf: support flash operations while the SoftDevice is enabled
- rp2040: allow writing to the UART inside interrupts
- machine,nrf528: stop the bus only once on I2C bus error and ensures the first error is returned
* **net**
- update submodule to latest commits
* **runtime**
- (avr): fix infinite longjmp loop if stack is aligned to 256 bytes
- (gc_blocks.go): clear full size of allocation
- (gc_blocks.go): make sweep branchless
- (gc_blocks.go): simplify scanning logic
- (gc_blocks.go): use a linked stack to scan marked objects
- (gc_blocks.go): use best-fit allocation
- (gc_boehm.go): fix world already stopped check
- (wasm): scan the system stack
- fix sleep duration for long sleeps
- remove copied code for nrf52840
- src/syscall: update src buffer after write
- wasm: fix C realloc and optimize it a bit
* **targets**
- add xiao-esp32s3 board target
- Add ESP32-S3 support (#5091)
- Added Gopher ARCADE board
- Create "pico2-ice" target board (#5062)
* **build/test**
- Add testing.T.Context() and testing.B.Context()
- create separate go.mod file for testing dependencies for wasm tests that use Chromium headless browser to avoid use of older incompatible version.
- go back to normal scheduler instead of tasks scheduler for macos CI
- update CI to use Go 1.25.5
- update macOS GH actions builds to handle sunset of macOS 13
- use task scheduler on macOS builds to avoid test race condition lockups
- update all CI builds to use latest stable Go release. Also update some of the actions to their latest releases.
- update GH actions builds to use Go 1.25.4
- uninstall cmake before install
- fix: point the submodule for musl-lib to a mirror in the TinyGo GitHub org
- fix: remove macOS 15 from CI build matrix (conflicts with macOS 14 build)
- fix: separate host expected bytes from device intended bytes
- fix/typo: makeESPFirmwareImage
- make: GNUmakefile: shrink TinyGo binaries on Linux
- move the directory list into a variable
- several improvements to the macOS GH actions build
- Fix for #4678: top-level 'make lint' wasn't working
- fix: increase the timeout for chromedp to connect to the headless browser used for running the wasm tests.
- testdata: some more packages for the test corpus
0.39.0
---
* **general**
- all: add Go 1.25 support
- net: update to latest tinygo net package
- docs: clarify build verification step for macOS users
- Add flag to skip Renesas SVD builds
* **build**
- Makefile: install missing dlmalloc files
- flash: add -o flag support to save built binary (Fixes #4937) (#4942)
- fix: update version of clang to 17 to accommodate latest Go 1.25 docker base image
* **ci**
- chore: update all CI builds to test Go 1.25 release
- fix: disable test-newest since CircleCI seems unable to download due to rate-limits on Dockerhub
- ci: rename some jobs to avoid churn on every Go/LLVM version bump
- ci: make the goroutines test less racy
- tests: de-flake goroutines test
* **compiler**
- compiler: implement internal/abi.Escape
* **main**
- main: show the compiler error (if any) for `tinygo test -c`
- chore: correct GOOS=js name in error messages for WASM
* **machine**
- machine: add international keys
- machine: remove some unnecessary "// peripherals:" comments
- machine: add I2C pin comments
- machine: standardize I2C errors with "i2c:" prefix
- machine: make I2C usable in the simulator
- fix: add SPI and I2C to teensy 4.1 (#4943)
- `rp2`: use the correct channel mask for rp2350 ADC; hold lock during read (#4938)
- `rp2`: disable digital input for analog inputs
* **runtime**
- runtime: ensure time.Sleep(d) sleeps at least d
- runtime: stub out weak pointer support
- runtime: implement dummy AddCleanup
- runtime: enable multi-core scheduler for rp2350
- `internal/task`: use -stack-size flag when starting a new thread
- `internal/task`: add SA_RESTART flag to GC interrupts
- `internal/task`: a few small correctness fixes
- `internal/gclayout`: make gclayout values constants
- darwin: add threading support and use it by default
* **standard library**
- `sync`: implement sync.Swap
- `reflect`: implement Method.IsExported
* **testing**
- testing: stub out testing.B.Loop
* **targets**
- `stm32`: add support for the STM32L031G6U6
- add metro-rp2350 board definition (#4989)
- `rp2040/rp2350`: set the default stack size to 8k for rp2040/rp2350 based boards where this was not already the case
0.38.0
---
* **general**
+3 -3
View File
@@ -1,8 +1,8 @@
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.26 AS tinygo-llvm
FROM golang:1.24 AS tinygo-llvm
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-17 ninja-build && \
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
rm -rf \
/var/lib/apt/lists/* \
/var/log/* \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc).
FROM golang:1.26 AS tinygo-compiler
FROM golang:1.24 AS tinygo-compiler
# Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+19 -119
View File
@@ -79,26 +79,6 @@ ifeq (1, $(STATIC))
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
endif
# Optimize the binary size for Linux.
# These flags may work on other platforms, but have only been tested on Linux.
ifeq ($(uname),Linux)
HAS_MOLD := $(shell command -v ld.mold 2> /dev/null)
HAS_LLD := $(shell command -v ld.lld 2> /dev/null)
LLVM_CFLAGS := -ffunction-sections -fdata-sections -fvisibility=hidden
LLVM_LDFLAGS := -Wl,--gc-sections
ifneq ($(HAS_MOLD),)
# Mold might be slightly faster.
LLVM_LDFLAGS += -fuse-ld=mold -Wl,--icf=all
else ifneq ($(HAS_LLD),)
# LLD is more commonly available.
LLVM_LDFLAGS += -fuse-ld=lld -Wl,--icf=all
endif
LLVM_OPTION += \
-DCMAKE_C_FLAGS="$(LLVM_CFLAGS)" \
-DCMAKE_CXX_FLAGS="$(LLVM_CFLAGS)"
CGO_LDFLAGS += $(LLVM_LDFLAGS)
endif
# Cross compiling support.
ifneq ($(CROSS),)
CC = $(CROSS)-gcc
@@ -263,7 +243,7 @@ gen-device-renesas: build/gen-device-svd
GO111MODULE=off $(GO) fmt ./src/device/renesas
$(LLVM_PROJECTDIR)/llvm:
git clone -b tinygo_20.x --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
git clone -b xtensa_release_19.1.2 --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources
# Configure LLVM.
@@ -289,13 +269,13 @@ WASM_TOOLS_MODULE=go.bytecodealliance.org
.PHONY: wasi-syscall
wasi-syscall: wasi-cm
rm -rf ./src/internal/wasi/*
go run $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
# Copy package cm into src/internal/cm
.PHONY: wasi-cm
wasi-cm:
rm -rf ./src/internal/cm/*
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
# Check for Node.js used during WASM tests.
MIN_NODEJS_VERSION=18
@@ -339,17 +319,14 @@ TEST_PACKAGES_FAST = \
embed/internal/embedtest \
encoding \
encoding/ascii85 \
errors \
encoding/asn1 \
encoding/base32 \
encoding/base64 \
encoding/csv \
encoding/hex \
expvar \
go/ast \
go/format \
go/scanner \
go/token \
go/version \
hash \
hash/adler32 \
@@ -362,7 +339,6 @@ TEST_PACKAGES_FAST = \
math/cmplx \
net/http/internal/ascii \
net/mail \
net/url \
os \
path \
reflect \
@@ -383,7 +359,6 @@ TEST_PACKAGES_FAST = \
# crypto/des fails on wasi, needs panic()/recover()
# 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
# encoding/xml takes a minute on linux and gives a stack overflow 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
# mime: fail on wasi; neds panic()/recover()
@@ -401,13 +376,11 @@ TEST_PACKAGES_FAST = \
TEST_PACKAGES_LINUX := \
archive/zip \
compress/flate \
context \
crypto/aes \
crypto/des \
crypto/hmac \
debug/dwarf \
debug/plan9obj \
encoding/xml \
image \
io/ioutil \
mime \
@@ -444,7 +417,6 @@ TEST_PACKAGES_NONWASM = \
crypto/ecdsa \
debug/macho \
embed/internal/embedtest \
expvar \
go/format \
os \
testing \
@@ -488,16 +460,11 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false
endif
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic|TestAsValidation'
TEST_ADDITIONAL_FLAGS ?=
# Test known-working standard library packages.
# TODO: parallelize, and only show failing tests (no implied -v flag).
.PHONY: tinygo-test
tinygo-test:
@# TestExtraMethods: used by many crypto packages and uses reflect.Type.Method which is not implemented.
@# TestParseAndBytesRoundTrip/P256/Generic: relies on t.Skip() which is not implemented
$(TINYGO) test $(TEST_ADDITIONAL_FLAGS) $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
@# requires a large stack-size. Hence, io/fs is only run conditionally.
@# For more details, see the comments on issue #3143.
@@ -505,7 +472,7 @@ ifeq ($(TEST_IOFS),true)
$(TINYGO) test -stack-size=6MB io/fs
endif
tinygo-test-fast:
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST)
$(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
@@ -513,18 +480,18 @@ tinygo-bench-fast:
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasm:
$(TINYGO) test -target wasm $(TEST_SKIP_FLAG) $(TEST_PACKAGES_WASM)
$(TINYGO) test -target wasm $(TEST_PACKAGES_WASM)
tinygo-test-wasi:
$(TINYGO) test -target wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1-fast:
$(TINYGO) test -target=wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
$(TINYGO) test -target=wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip2-slow:
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_SLOW)
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
tinygo-test-wasip2-fast:
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip2-sum-slow:
TINYGO=$(TINYGO) \
@@ -550,7 +517,7 @@ tinygo-bench-wasip2-fast:
# Run tests on riscv-qemu since that one provides a large amount of memory.
tinygo-test-baremetal:
$(TINYGO) test -target riscv-qemu $(TEST_SKIP_FLAG) $(TEST_PACKAGES_BAREMETAL)
$(TINYGO) test -target riscv-qemu $(TEST_PACKAGES_BAREMETAL)
# Test external packages in a large corpus.
test-corpus:
@@ -630,11 +597,9 @@ smoketest: testchdir
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
ifneq ($(WASM), 0)
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
@$(MD5SUM) test.wasm
@@ -652,8 +617,6 @@ ifneq ($(WASM), 0)
@$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
@$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=xiao_esp32s3 examples/blinky1
@$(MD5SUM) test.wasm
endif
# test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@@ -808,8 +771,6 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gopher-arcade examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
@@ -820,14 +781,8 @@ endif
@$(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=metro-rp2350 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=vicharak_shrike-lite examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao-rp2350 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
@@ -887,24 +842,18 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinkm
@$(MD5SUM) test.hex
endif
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/blinky1
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/pwm
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno -scheduler=tasks examples/blinky1
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
@$(MD5SUM) test.hex
@@ -916,25 +865,13 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/mcp3008
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@$(MD5SUM) test.hex
ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target=esp32-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(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=esp32c3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
@@ -947,39 +884,7 @@ ifneq ($(XTENSA), 0)
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
@$(MD5SUM) test.bin
# xiao-esp32s3
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/pwm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/adc
@$(MD5SUM) test.bin
# esp32s3-supermini
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/adc
@$(MD5SUM) test.bin
endif
# esp32c3-supermini
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/pwm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/adc
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
@@ -992,7 +897,6 @@ endif
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@@ -1041,7 +945,7 @@ endif
wasmtest:
cd ./tests/wasm && $(GO) test .
$(GO) test ./tests/wasm
build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
@mkdir -p build/release/tinygo/bin
@@ -1186,9 +1090,8 @@ endif
.PHONY: tools
tools:
go generate -tags tools ./
cd internal/tools && go generate -tags tools ./
LINTDIRS=src/os/ src/reflect/
.PHONY: lint
lint: tools ## Lint source tree
revive -version
@@ -1196,10 +1099,7 @@ lint: tools ## Lint source tree
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
# Use 'grep .' to get rid of stray blank line
revive -config revive.toml compiler/... $$( find $(LINTDIRS) -type f -name '*.go' ) \
| grep -v "should have comment or be unexported" \
| grep '.' \
| awk '{print}; END {exit NR>0}'
revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
SPELLDIRSCMD=find . -depth 1 -type d | egrep -wv '.git|lib|llvm|src'; find src -depth 1 | egrep -wv 'device|internal|net|vendor'; find src/internal -depth 1 -type d | egrep -wv src/internal/wasi
.PHONY: spell
+2 -3
View File
@@ -1,8 +1,7 @@
Copyright (c) 2018-2026 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2025 The TinyGo Authors. All rights reserved.
TinyGo includes portions of the Go standard library.
Copyright 2009 The Go Authors. All rights reserved.
See https://github.com/golang/go/blob/master/LICENSE for license information.
Copyright (c) 2009-2024 The Go Authors. All rights reserved.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
+6 -9
View File
@@ -1,14 +1,11 @@
# TinyGo - Go compiler for small places
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml)
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
> [!IMPORTANT]
> You can help TinyGo with a financial contribution using OpenCollective. Please see https://opencollective.com/tinygo for more information. Thank you!
## Embedded
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
@@ -34,10 +31,10 @@ func main() {
}
```
The above program can be compiled and run without modification on an [Arduino Uno](https://tinygo.org/docs/reference/microcontrollers/boards/arduino-uno), an [Adafruit Circuit Playground Express](https://tinygo.org/docs/reference/microcontrollers/featured/circuitplay-express), a [Seeed Studio XIAO-ESP32S3](https://tinygo.org/docs/reference/microcontrollers/featured/xiao-esp32s3) or any of the many supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
The above program can be compiled and run without modification on an Arduino Uno, an Adafruit ItsyBitsy M0, or any of the supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
```shell
tinygo flash -target arduino-uno examples/blinky1
tinygo flash -target arduino examples/blinky1
```
## WebAssembly
@@ -66,7 +63,7 @@ tinygo build -buildmode=c-shared -o add.wasm -target=wasip1 add.go
You can also use the same syntax as Go 1.24+:
```shell
GOOS=wasip1 GOARCH=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
GOARCH=wasip1 GOOS=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
```
## Installation
@@ -77,7 +74,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
### Embedded
You can compile TinyGo programs for over 150 different microcontroller boards.
You can compile TinyGo programs for over 94 different microcontroller boards.
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
@@ -142,7 +139,7 @@ Non-goals:
## Why this project exists
> We never expected Go to be an embedded language, and so its got serious problems...
> We never expected Go to be an embedded language and so its got serious problems...
-- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799)
+3 -6
View File
@@ -30,10 +30,7 @@ var BoehmGC = Library{
// Use a minimal environment.
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
"-DDONT_USE_ATEXIT",
"-DNO_GETENV", // smaller binary, more predictable configuration
"-DNO_CLOCK", // don't use system clock
"-DNO_DEBUGGING", // reduce code size
"-DGC_NO_FINALIZATION", // finalization is not used at the moment
"-DNO_GETENV",
// Special flag to work around the lack of __data_start in ld.lld.
// TODO: try to fix this in LLVM/lld directly so we don't have to
@@ -42,8 +39,6 @@ var BoehmGC = Library{
// Do not scan the stack. We have our own mechanism to do this.
"-DSTACK_NOT_SCANNED",
"-DNO_PROC_STAT", // we scan the stack manually (don't read /proc/self/stat on Linux)
"-DSTACKBOTTOM=0", // dummy value, we scan the stack manually
// Assertions can be enabled while debugging GC issues.
//"-DGC_ASSERTIONS",
@@ -68,6 +63,7 @@ var BoehmGC = Library{
"blacklst.c",
"dbg_mlc.c",
"dyn_load.c",
"finalize.c",
"headers.c",
"mach_dep.c",
"malloc.c",
@@ -75,6 +71,7 @@ var BoehmGC = Library{
"mark_rts.c",
"misc.c",
"new_hblk.c",
"obj_map.c",
"os_dep.c",
"reclaim.c",
}
+8 -42
View File
@@ -19,7 +19,6 @@ import (
"os/exec"
"path/filepath"
"runtime"
"slices"
"sort"
"strconv"
"strings"
@@ -255,18 +254,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
}
// Strip default initializers for -X globals from the type info before
// building SSA. This prevents go/ssa from emitting init stores for them,
// so that makeGlobalsModule can supply the correct values at final link
// time without any runtime init overwriting them. The -X values themselves
// are kept out of the per-package build cache; only the variable names
// appear in the cache key.
for _, pkg := range lprogram.Sorted() {
for name := range globalValues[pkg.Pkg.Path()] {
pkg.StripVarInitializer(name)
}
}
// 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 := lprogram.LoadSSA()
@@ -294,13 +281,9 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
allFiles[file.Name] = append(allFiles[file.Name], file)
}
}
// Sort embedded files by name to maintain output determinism.
embedNames := make([]string, 0, len(allFiles))
for _, files := range allFiles {
embedNames = append(embedNames, files[0].Name)
}
slices.Sort(embedNames)
for _, name := range embedNames {
for name, files := range allFiles {
name := name
files := files
job := &compileJob{
description: "make object file for " + name,
run: func(job *compileJob) error {
@@ -315,7 +298,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
sum := sha256.Sum256(data)
hexSum := hex.EncodeToString(sum[:16])
for _, file := range allFiles[name] {
for _, file := range files {
file.Size = uint64(len(data))
file.Hash = hexSum
if file.NeedsData {
@@ -489,7 +472,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path())
}
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA())
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
if err != nil {
return err
}
@@ -558,23 +541,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil {
return fmt.Errorf("failed to load bitcode file: %w", err)
}
// Resolve duplicate function definitions before linking.
// This can happen when a newer Go version adds a function
// body in a standard library package that was previously
// just a declaration provided by //go:linkname from the
// runtime. In that case, keep the existing (runtime)
// definition by weakening the new one's linkage so the
// LLVM linker discards it in favor of the existing one.
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
if fn.IsDeclaration() {
continue
}
existing := mod.NamedFunction(fn.Name())
if existing.IsNil() || existing.IsDeclaration() {
continue
}
fn.SetLinkage(llvm.LinkOnceODRLinkage)
}
err = llvm.LinkModules(mod, pkgMod)
if err != nil {
return fmt.Errorf("failed to link module: %w", err)
@@ -1076,11 +1042,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil {
return result, err
}
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp8266":
case "esp32", "esp32-img", "esp32c3", "esp8266":
// Special format for the ESP family of chips (parsed by the ROM
// bootloader).
result.Binary = filepath.Join(tmpdir, "main"+outext)
err := makeESPFirmwareImage(result.Executable, result.Binary, outputBinaryFormat)
err := makeESPFirmareImage(result.Executable, result.Binary, outputBinaryFormat)
if err != nil {
return result, err
}
@@ -1208,7 +1174,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
// needed to convert a program to its final form. Some transformations are not
// optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
err := interp.Run(mod, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA())
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
if err != nil {
return err
}
-1
View File
@@ -28,7 +28,6 @@ func TestClangAttributes(t *testing.T) {
"cortex-m4",
"cortex-m7",
"esp32c3",
"esp32s3",
"fe310",
"gameboy-advance",
"k210",
+8 -13
View File
@@ -144,6 +144,8 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Default(llvm::DebugCompressionType::None);
}
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.SSE2AVX = Args.hasArg(OPT_msse2avx);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
@@ -234,9 +236,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.EmitCompactUnwindNonCanonical =
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
Opts.Crel = Args.hasArg(OPT_crel);
Opts.ImplicitMapsyms = Args.hasArg(OPT_mmapsyms_implicit);
Opts.X86RelaxRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.X86Sse2Avx = Args.hasArg(OPT_msse2avx);
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
@@ -295,9 +294,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
MCOptions.Crel = Opts.Crel;
MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations;
MCOptions.X86Sse2Avx = Opts.SSE2AVX;
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
@@ -345,6 +343,10 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(Ctx, PIC));
if (Opts.DarwinTargetVariantTriple)
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
if (!Opts.DarwinTargetVariantSDKVersion.empty())
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
Ctx.setObjectFileInfo(MOFI.get());
if (Opts.GenDwarfForAssembly)
@@ -426,13 +428,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Str.reset(TheTarget->createMCObjectStreamer(
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
Str.get()->initSections(Opts.NoExecStack, *STI);
if (T.isOSBinFormatMachO() && T.isOSDarwin()) {
Triple *TVT = Opts.DarwinTargetVariantTriple
? &*Opts.DarwinTargetVariantTriple
: nullptr;
Str->emitVersionForTarget(T, VersionTuple(), TVT,
Opts.DarwinTargetVariantSDKVersion);
}
}
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
+6 -11
View File
@@ -45,6 +45,10 @@ struct AssemblerInvocation {
LLVM_PREFERRED_TYPE(bool)
unsigned GenDwarfForAssembly : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned RelaxELFRelocations : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SSE2AVX : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Dwarf64 : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
@@ -107,19 +111,12 @@ struct AssemblerInvocation {
EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries.
// Note: maybe overridden by other constraints.
// Note: maybe overriden by other constraints.
LLVM_PREFERRED_TYPE(bool)
unsigned EmitCompactUnwindNonCanonical : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Crel : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned ImplicitMapsyms : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned X86RelaxRelocations : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned X86Sse2Avx : 1;
/// The name of the relocation model to use.
std::string RelocationModel;
@@ -151,6 +148,7 @@ public:
ShowInst = 0;
ShowEncoding = 0;
RelaxAll = 0;
SSE2AVX = 0;
NoExecStack = 0;
FatalWarnings = 0;
NoWarn = 0;
@@ -162,9 +160,6 @@ public:
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
EmitCompactUnwindNonCanonical = false;
Crel = false;
ImplicitMapsyms = 0;
X86RelaxRelocations = 0;
X86Sse2Avx = 0;
}
static bool CreateFromArgs(AssemblerInvocation &Res,
+1 -1
View File
@@ -60,7 +60,7 @@ bool tinygo_clang_driver(int argc, char **argv) {
}
// Create the actual diagnostics engine.
Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
Clang->createDiagnostics();
if (!Clang->hasDiagnostics()) {
return false;
}
+5 -8
View File
@@ -26,20 +26,17 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
// Version range supported by TinyGo.
const minorMin = 19
const minorMax = 26
const minorMax = 24
// Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
if err != nil {
return nil, err
}
if options.GoCompatibility {
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
// Note: when this gets updated, also update the Go compatibility matrix:
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
}
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
// Note: when this gets updated, also update the Go compatibility matrix:
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
}
// Check that the Go toolchain version isn't too new, if we haven't been
+3 -4
View File
@@ -23,7 +23,7 @@ type espImageSegment struct {
data []byte
}
// makeESPFirmwareImage converts an input ELF file to an image file for an ESP32 or
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
// ESP8266 chip. This is a special purpose image format just for the ESP chip
// family, and is parsed by the on-chip mask ROM bootloader.
//
@@ -31,7 +31,7 @@ type espImageSegment struct {
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
// https://github.com/espressif/esptool/blob/master/esptool.py
func makeESPFirmwareImage(infile, outfile, format string) error {
func makeESPFirmareImage(infile, outfile, format string) error {
inf, err := elf.Open(infile)
if err != nil {
return err
@@ -100,12 +100,11 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
chip_id := map[string]uint16{
"esp32": 0x0000,
"esp32c3": 0x0005,
"esp32s3": 0x0009,
}[chip]
// Image header.
switch chip {
case "esp32", "esp32c3", "esp32s3":
case "esp32", "esp32c3":
// Header format:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
// Note: not adding a SHA256 hash as the binary is modified by
+2 -16
View File
@@ -167,9 +167,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// double.
args = append(args, "-mdouble=64")
case "riscv32":
args = append(args, "-march="+riscvMarch(config, "rv32imac"), "-fforce-enable-int128")
args = append(args, "-march=rv32imac", "-fforce-enable-int128")
case "riscv64":
args = append(args, "-march="+riscvMarch(config, "rv64gc"))
args = append(args, "-march=rv64gc")
case "mips":
args = append(args, "-fno-pic")
}
@@ -298,17 +298,3 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
once.Do(unlock)
}, nil
}
// riscvMarch returns the -march value for RISC-V library compilation.
// It extracts the value from the target's cflags if present, otherwise
// falls back to the provided default. This ensures libraries are compiled
// with the correct ISA extensions for each target (e.g. rv32imc for
// ESP32-C3 which lacks the atomic extension).
func riscvMarch(config *compileopts.Config, defaultMarch string) string {
for _, flag := range config.Target.CFlags {
if strings.HasPrefix(flag, "-march=") {
return flag[len("-march="):]
}
}
return defaultMarch
}
+1 -5
View File
@@ -954,11 +954,7 @@ func findPackagePath(path string, packagePathMap map[string]string) (packagePath
libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator))
parts := strings.SplitN(libPath, string(os.PathSeparator), 2)
packagePath = "C " + parts[0]
if len(parts) > 1 {
filename = parts[1]
} else {
filename = 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"
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
+3 -3
View File
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test.
tests := []sizeTest{
// microcontrollers
{"hifive1b", "examples/echo", 3680, 280, 0, 2252},
{"microbit", "examples/serial", 2694, 342, 8, 2248},
{"wioterminal", "examples/pininterrupt", 7074, 1510, 120, 7248},
{"hifive1b", "examples/echo", 4556, 280, 0, 2264},
{"microbit", "examples/serial", 2920, 388, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7379, 1489, 116, 6912},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
+1 -1
View File
@@ -28,7 +28,7 @@ func RunTool(tool string, args ...string) error {
var cflag *C.char
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
defer C.free(buf)
cflags := unsafe.Slice((**C.char)(buf), len(args))
cflags := (*[1 << 10]*C.char)(unsafe.Pointer(buf))[:len(args):len(args)]
for i, flag := range args {
cflag := C.CString(flag)
cflags[i] = cflag
+1 -5
View File
@@ -122,16 +122,12 @@ func parseLLDErrors(text string) error {
parsedError = true
line, _ := strconv.Atoi(matches[3])
// TODO: detect common mistakes like -gc=none?
msg := "linker could not find symbol " + symbolName
if symbolName == "runtime.alloc_noheap" {
msg = "object allocated on the heap in //go:noheap function"
}
linkErrors = append(linkErrors, scanner.Error{
Pos: token.Position{
Filename: matches[2],
Line: line,
},
Msg: msg,
Msg: "linker could not find symbol " + symbolName,
})
}
}
+3 -3
View File
@@ -130,7 +130,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
// convert Go slice of strings to C array of strings.
cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0))))
defer C.free(cmdargsC)
cmdargs := unsafe.Slice((**C.char)(cmdargsC), len(cflags))
cmdargs := (*[1 << 16]*C.char)(cmdargsC)
for i, cflag := range cflags {
s := C.CString(cflag)
cmdargs[i] = s
@@ -190,7 +190,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
// Sanity check. This should (hopefully) never trigger.
panic("libclang: file contents was not loaded")
}
data := unsafe.Slice((*byte)(unsafe.Pointer(rawData)), size)
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
// Hash the contents if it isn't hashed yet.
if _, ok := f.visitedFiles[path]; !ok {
@@ -624,7 +624,7 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
// now by reading the file from libclang.
var size C.size_t
sourcePtr := C.clang_getFileContents(tu, file, &size)
source := unsafe.Slice((*byte)(unsafe.Pointer(sourcePtr)), size)
source := ((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[:size:size]
lines := []int{0}
for i := 0; i < len(source)-1; i++ {
if source[i] == '\n' {
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include -I/usr/lib64/llvm19/include
#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
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include -I/usr/lib64/llvm20/include
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
#cgo freebsd CFLAGS: -I/usr/local/llvm20/include
-1
View File
@@ -78,7 +78,6 @@ var validCompilerFlags = []*regexp.Regexp{
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?plt`),
re(`-f(no-)?rtti`),
re(`-f(no-)?short-enums`),
re(`-f(no-)?split-stack`),
re(`-f(no-)?stack-(.+)`),
re(`-f(no-)?strict-aliasing`),
+2 -2
View File
@@ -226,7 +226,7 @@ func (c *Config) StackSize() uint64 {
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
func (c *Config) MaxStackAlloc() uint64 {
if c.StackSize() >= 16*1024 {
if c.StackSize() > 32*1024 {
return 1024
}
@@ -536,7 +536,7 @@ func (c *Config) Programmer() (method, openocdInterface string) {
case "":
// No configuration supplied.
return c.Target.FlashMethod, c.Target.OpenOCDInterface
case "openocd", "msd", "command", "adb":
case "openocd", "msd", "command":
// The -programmer flag only specifies the flash method.
return c.Options.Programmer, c.Target.OpenOCDInterface
case "bmp":
+38 -40
View File
@@ -21,46 +21,44 @@ var (
// usually passed from the command line, but can also be passed in environment
// variables for example.
type Options struct {
GOOS string // environment variable
GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm)
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
Directory string // working dir, leave it unset to use the current working dir
Target string
BuildMode string // -buildmode flag
Opt string
GC string
PanicStrategy string
Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string
Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration
InterpMaxLoopIterations int
PrintIR bool
DumpSSA bool
VerifyIR bool
SkipDWARF bool
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
Nobounds bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool
Tags []string
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
TestConfig TestConfig
Programmer string
OpenOCDCommands []string
LLVMFeatures string
Monitor bool
BaudRate int
Timeout time.Duration
WITPackage string // pass through to wasm-tools component embed invocation
WITWorld string // pass through to wasm-tools component embed -w option
ExtLDFlags []string
GoCompatibility bool // enable to check for Go version compatibility
GOOS string // environment variable
GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm)
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
Directory string // working dir, leave it unset to use the current working dir
Target string
BuildMode string // -buildmode flag
Opt string
GC string
PanicStrategy string
Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string
Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration
PrintIR bool
DumpSSA bool
VerifyIR bool
SkipDWARF bool
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
Nobounds bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool
Tags []string
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
TestConfig TestConfig
Programmer string
OpenOCDCommands []string
LLVMFeatures string
Monitor bool
BaudRate int
Timeout time.Duration
WITPackage string // pass through to wasm-tools component embed invocation
WITWorld string // pass through to wasm-tools component embed -w option
ExtLDFlags []string
}
// Verify performs a validation on the given options, raising an error if options are not valid.
-19
View File
@@ -24,7 +24,6 @@ import (
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct {
Inherits []string `json:"inherits,omitempty"`
InheritableOnly bool `json:"inheritable-only"` // this target is only meant to be inherited from, not used directly
Triple string `json:"llvm-target,omitempty"`
CPU string `json:"cpu,omitempty"`
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
@@ -64,9 +63,6 @@ type TargetSpec struct {
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device,omitempty"`
ADBPreCommands []string `json:"adb-pre-commands,omitempty"`
ADBPushRemote string `json:"adb-push-remote,omitempty"`
ADBPostCommands []string `json:"adb-post-commands,omitempty"`
CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"`
WITPackage string `json:"wit-package,omitempty"`
@@ -152,11 +148,6 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
// resolveInherits loads inherited targets, recursively.
func (spec *TargetSpec) resolveInherits() error {
// Save InheritableOnly before resolving, since it must not propagate
// from parent to child (a board target should not become inheritable-only
// just because its parent processor target is).
inheritableOnly := spec.InheritableOnly
// First create a new spec with all the inherited properties.
newSpec := &TargetSpec{}
for _, name := range spec.Inherits {
@@ -182,9 +173,6 @@ func (spec *TargetSpec) resolveInherits() error {
}
*spec = *newSpec
// Restore InheritableOnly from the original spec, not from parents.
spec.InheritableOnly = inheritableOnly
return nil
}
@@ -251,17 +239,10 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
continue
}
path := filepath.Join(dir, entry.Name())
spec, err := LoadTarget(&Options{Target: path})
if err != nil {
return nil, fmt.Errorf("could not list target: %w", err)
}
if spec.InheritableOnly {
// Skip targets that are only meant to be inherited from, not used directly.
continue
}
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json).
-31
View File
@@ -23,37 +23,6 @@ func TestLoadTarget(t *testing.T) {
}
}
func TestGetTargetSpecs_InheritableOnlyTargetsExcluded(t *testing.T) {
specs, err := GetTargetSpecs()
if err != nil {
t.Fatal("GetTargetSpecs failed:", err)
}
// Inheritable-only processor-level targets should not appear in the listing.
inheritableOnlyTargets := []string{"esp32", "esp32c3", "esp32s3", "esp8266", "rp2040", "rp2350", "rp2350b"}
for _, name := range inheritableOnlyTargets {
if _, ok := specs[name]; ok {
t.Errorf("inheritable-only target %q should not appear in GetTargetSpecs", name)
}
}
// Board targets that inherit from inheritable-only targets should still appear.
boardTargets := []string{"esp32-coreboard-v2", "pico"}
for _, name := range boardTargets {
if _, ok := specs[name]; !ok {
t.Errorf("board target %q should appear in GetTargetSpecs", name)
}
}
}
func TestLoadTarget_InheritableOnlyTargetStillLoadable(t *testing.T) {
// Inheritable-only targets should still be loadable directly (for building).
_, err := LoadTarget(&Options{Target: "esp32"})
if err != nil {
t.Errorf("LoadTarget should still load inheritable-only target esp32: %v", err)
}
}
func TestOverrideProperties(t *testing.T) {
baseAutoStackSize := true
base := &TargetSpec{
+1 -1
View File
@@ -245,7 +245,7 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
// current insert position.
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block.
b.CreateCondBr(assert, faultBlock, nextBlock)
-8
View File
@@ -32,9 +32,6 @@ const (
// Whether this is a full or partial Go parameter (int, slice, etc).
// The extra context parameter is not a Go parameter.
paramIsGoParam = 1 << iota
// Whether this is a readonly parameter (for example, a string pointer).
paramIsReadonly
)
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
@@ -170,7 +167,6 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
continue
}
suffix := strconv.Itoa(i)
isString := false
if goType != nil {
// Try to come up with a good suffix for this struct field,
// depending on which Go type it's based on.
@@ -187,16 +183,12 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
suffix = []string{"r", "i"}[i]
case types.String:
suffix = []string{"data", "len"}[i]
isString = true
}
case *types.Signature:
suffix = []string{"context", "funcptr"}[i]
}
}
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
if isString {
subInfos[0].flags |= paramIsReadonly
}
paramInfos = append(paramInfos, subInfos...)
}
return paramInfos
+34 -153
View File
@@ -152,12 +152,10 @@ type builder struct {
llvmFnType llvm.Type
llvmFn llvm.Value
info functionInfo
locals map[ssa.Value]llvm.Value // local variables
blockInfo []blockInfo
locals map[ssa.Value]llvm.Value // local variables
blockEntries map[*ssa.BasicBlock]llvm.BasicBlock // a *ssa.BasicBlock may be split up
blockExits map[*ssa.BasicBlock]llvm.BasicBlock // these are the exit blocks
currentBlock *ssa.BasicBlock
currentBlockInfo *blockInfo
tarjanStack []uint
tarjanIndex uint
phis []phiNode
deferPtr llvm.Value
deferFrame llvm.Value
@@ -189,32 +187,11 @@ func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *bu
info: c.getFunctionInfo(f),
locals: make(map[ssa.Value]llvm.Value),
dilocals: make(map[*types.Var]llvm.Metadata),
blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock),
blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock),
}
}
// Return the runtime.alloc function variant.
// This is normally just "alloc", but is "alloc_noheap" if the //go:noheap
// pragma is used.
func (b *builder) allocFunc() string {
if b.info.noheap {
return "alloc_noheap"
}
return "alloc"
}
type blockInfo struct {
// entry is the LLVM basic block corresponding to the start of this *ssa.Block.
entry llvm.BasicBlock
// exit is the LLVM basic block corresponding to the end of this *ssa.Block.
// It will be different than entry if any of the block's instructions contain internal branches.
exit llvm.BasicBlock
// tarjan holds state for applying Tarjan's strongly connected components algorithm to the CFG.
// This is used by defer.go to determine whether to stack- or heap-allocate defer data.
tarjan tarjanNode
}
type deferBuiltin struct {
callName string
pos token.Pos
@@ -324,6 +301,9 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Load comments such as //go:extern on globals.
c.loadASTComments(pkg)
// Predeclare the runtime.alloc function, which is used by the wordpack
// functionality.
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
if c.NeedsStackObjects {
// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
@@ -880,10 +860,6 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
// with a LLVM intrinsic.
continue
}
if ok := b.defineCryptoIntrinsic(); ok {
// Body of this function was replaced
continue
}
if member.Blocks == nil {
// Try to define this as an intrinsic function.
b.defineIntrinsicFunction()
@@ -1244,29 +1220,14 @@ func (b *builder) createFunctionStart(intrinsic bool) {
// intrinsic (like an atomic operation). Create the entry block
// manually.
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
// Intrinsics may create internal branches (e.g. nil checks).
// They will attempt to access b.currentBlockInfo to update the exit block.
// Create some fake block info for them to access.
blockInfo := []blockInfo{
{
entry: entryBlock,
exit: entryBlock,
},
}
b.blockInfo = blockInfo
b.currentBlockInfo = &blockInfo[0]
} else {
blocks := b.fn.Blocks
blockInfo := make([]blockInfo, len(blocks))
for _, block := range b.fn.DomPreorder() {
info := &blockInfo[block.Index]
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
info.entry = llvmBlock
info.exit = llvmBlock
b.blockEntries[block] = llvmBlock
b.blockExits[block] = llvmBlock
}
b.blockInfo = blockInfo
// Normal functions have an entry block.
entryBlock = blockInfo[0].entry
entryBlock = b.blockEntries[b.fn.Blocks[0]]
}
b.SetInsertPointAtEnd(entryBlock)
@@ -1362,9 +1323,8 @@ func (b *builder) createFunction() {
if b.DumpSSA {
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
}
b.SetInsertPointAtEnd(b.blockEntries[block])
b.currentBlock = block
b.currentBlockInfo = &b.blockInfo[block.Index]
b.SetInsertPointAtEnd(b.currentBlockInfo.entry)
for _, instr := range block.Instrs {
if instr, ok := instr.(*ssa.DebugRef); ok {
if !b.Debug {
@@ -1424,7 +1384,7 @@ func (b *builder) createFunction() {
block := phi.ssa.Block()
for i, edge := range phi.ssa.Edges {
llvmVal := b.getValue(edge, getPos(phi.ssa))
llvmBlock := b.blockInfo[block.Preds[i].Index].exit
llvmBlock := b.blockExits[block.Preds[i]]
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
}
}
@@ -1538,11 +1498,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
case *ssa.If:
cond := b.getValue(instr.Cond, getPos(instr))
block := instr.Block()
blockThen := b.blockInfo[block.Succs[0].Index].entry
blockElse := b.blockInfo[block.Succs[1].Index].entry
blockThen := b.blockEntries[block.Succs[0]]
blockElse := b.blockEntries[block.Succs[1]]
b.CreateCondBr(cond, blockThen, blockElse)
case *ssa.Jump:
blockJump := b.blockInfo[instr.Block().Succs[0].Index].entry
blockJump := b.blockEntries[instr.Block().Succs[0]]
b.CreateBr(blockJump)
case *ssa.MapUpdate:
m := b.getValue(instr.Map, getPos(instr))
@@ -1610,8 +1570,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
elemLayout := b.createObjectLayout(elemType, pos)
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize, elemLayout}, "append.new")
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
newLen := b.CreateExtractValue(result, 1, "append.newLen")
newCap := b.CreateExtractValue(result, 2, "append.newCap")
@@ -1693,41 +1652,13 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
case "copy":
dst := argValues[0]
src := argValues[1]
// Fetch the lengths.
dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen")
srcLen := b.CreateExtractValue(src, 1, "copy.srcLen")
// Find the minimum of the lengths.
minFuncName := "llvm.umin.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
minFunc := b.mod.NamedFunction(minFuncName)
if minFunc.IsNil() {
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType, b.uintptrType}, false)
minFunc = llvm.AddFunction(b.mod, minFuncName, fnType)
}
minLen := b.CreateCall(minFunc.GlobalValueType(), minFunc, []llvm.Value{dstLen, srcLen}, "copy.n")
// Multiply the length by the element size.
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
// NOTE: This is also NSW when uintptr is int, but we can only choose one through the C API?
size := b.CreateNUWMul(minLen, elemSize, "copy.size")
// Fetch the pointers.
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstPtr")
srcBuf := b.CreateExtractValue(src, 0, "copy.srcPtr")
// Create a memcpy.
call := b.createMemCopy("memmove", dstBuf, srcBuf, size)
align := b.targetData.ABITypeAlignment(elemType)
if align > 1 {
// Apply the type's alignment to the arguments.
// LLVM sometimes turns constant-length moves into loads and stores.
// It may use this alignment for the created loads and stores.
alignAttr := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))
call.AddCallSiteAttribute(1, alignAttr)
call.AddCallSiteAttribute(2, alignAttr)
}
// Extend and return the copied length.
if b.targetData.TypeAllocSize(minLen.Type()) < b.targetData.TypeAllocSize(b.intType) {
minLen = b.CreateZExt(minLen, b.intType, "copy.n.zext")
}
return minLen, nil
return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
case "delete":
m := argValues[0]
key := argValues[1]
@@ -1755,66 +1686,20 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
return llvmLen, nil
case "min", "max":
// min and max builtins, added in Go 1.21.
// Find the corresponding intrinsic name.
ty := argTypes[0].Underlying().(*types.Basic)
llvmType := b.getLLVMType(ty)
info := ty.Info()
var prefix, delimeter, typeName string
if info&types.IsInteger != 0 {
// This is an integer value.
// Use the LLVM int min/max intrinsics.
prefix = "llvm.s"
if info&types.IsUnsigned != 0 {
prefix = "llvm.u"
}
delimeter = ".i"
typeName = strconv.Itoa(llvmType.IntTypeWidth())
} else {
switch ty.Kind() {
case types.String:
// Strings do not have an equivalent intrinsic.
// Implement with compares and selects.
tok := token.LSS
if callName == "max" {
tok = token.GTR
}
result := argValues[0]
typ := argTypes[0]
for _, arg := range argValues[1:] {
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
if err != nil {
return result, err
}
result = b.CreateSelect(cmp, result, arg, "")
}
return result, nil
case types.Float32:
typeName = "f32"
case types.Float64:
typeName = "f64"
default:
return llvm.Value{}, b.makeError(pos, "todo: min/max: unknown type")
}
// There are a few edge cases with floating point min/max:
// min(-0.0, +0.0) = -0.0
// min(NaN, number) = NaN
// The llvm.minimum.*/llvm.maximum.* intrinsics match this behavior.
// Neither Go nor LLVM defines the bit representation of resulting NaNs.
prefix = "llvm."
delimeter = "imum."
// We can simply reuse the existing binop comparison code, which has all
// the edge cases figured out already.
tok := token.LSS
if callName == "max" {
tok = token.GTR
}
intrinsicName := prefix + callName + delimeter + typeName
// Find or create the intrinsic.
llvmFn := b.mod.NamedFunction(intrinsicName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(llvmType, []llvm.Type{llvmType, llvmType}, false)
llvmFn = llvm.AddFunction(b.mod, intrinsicName, fnType)
}
// Call the intrinsic repeatedly to merge the arguments.
callType := llvmFn.GlobalValueType()
result := argValues[0]
typ := argTypes[0]
for _, arg := range argValues[1:] {
result = b.CreateCall(callType, llvmFn, []llvm.Value{result, arg}, "")
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
if err != nil {
return result, err
}
result = b.CreateSelect(cmp, result, arg, "")
}
return result, nil
case "panic":
@@ -1987,14 +1872,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.emitSV64Call(instr.Args, getPos(instr))
case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr)
case (strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall")) && name != "syscall.SyscallN":
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
if b.GOOS != "darwin" {
return b.createSyscall(instr)
}
case name == "syscall.syscalln":
if b.GOOS == "windows" {
return b.createSyscalln(instr)
}
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
return b.createRawSyscallNoError(instr)
case name == "runtime.supportsRecover":
@@ -2183,7 +2064,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
}
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
layoutValue := b.createObjectLayout(typ, expr.Pos())
buf := b.createRuntimeCall(b.allocFunc(), []llvm.Value{sizeValue, layoutValue}, expr.Comment)
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
align := b.targetData.ABITypeAlignment(typ)
buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
return buf, nil
@@ -2415,7 +2296,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
}
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
slicePtr := b.createRuntimeCall(b.allocFunc(), []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
// Extend or truncate if necessary. This is safe as we've already done
-1
View File
@@ -50,7 +50,6 @@ func TestCompiler(t *testing.T) {
{"channel.go", "", ""},
{"gc.go", "", ""},
{"zeromap.go", "", ""},
{"generics.go", "", ""},
}
if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""})
+30 -100
View File
@@ -100,7 +100,7 @@ func (b *builder) createLandingPad() {
// Continue at the 'recover' block, which returns to the parent in an
// appropriate way.
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
b.CreateBr(b.blockEntries[b.fn.Recover])
}
// Create a checkpoint (similar to setjmp). This emits inline assembly that
@@ -234,108 +234,41 @@ func (b *builder) createInvokeCheckpoint() {
continueBB := b.insertBasicBlock("")
b.CreateCondBr(isZero, continueBB, b.landingpad)
b.SetInsertPointAtEnd(continueBB)
b.currentBlockInfo.exit = continueBB
b.blockExits[b.currentBlock] = continueBB
}
// isInLoop checks if there is a path from the current block to itself.
// Use Tarjan's strongly connected components algorithm to search for cycles.
// A one-node SCC is a cycle iff there is an edge from the node to itself.
// A multi-node SCC is always a cycle.
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
func (b *builder) isInLoop() bool {
if b.currentBlockInfo.tarjan.lowLink == 0 {
b.strongConnect(b.currentBlock)
}
return b.currentBlockInfo.tarjan.cyclic
}
// isInLoop checks if there is a path from a basic block to itself.
func isInLoop(start *ssa.BasicBlock) bool {
// Use a breadth-first search to scan backwards through the block graph.
queue := []*ssa.BasicBlock{start}
checked := map[*ssa.BasicBlock]struct{}{}
func (b *builder) strongConnect(block *ssa.BasicBlock) {
// Assign a new index.
// Indices start from 1 so that 0 can be used as a sentinel.
assignedIndex := b.tarjanIndex + 1
b.tarjanIndex = assignedIndex
for len(queue) > 0 {
// pop a block off of the queue
block := queue[len(queue)-1]
queue = queue[:len(queue)-1]
// Apply the new index.
blockIndex := block.Index
node := &b.blockInfo[blockIndex].tarjan
node.lowLink = assignedIndex
// Push the node onto the stack.
node.onStack = true
b.tarjanStack = append(b.tarjanStack, uint(blockIndex))
// Process the successors.
for _, successor := range block.Succs {
// Look up the successor's state.
successorIndex := successor.Index
if successorIndex == blockIndex {
// Handle a self-cycle specially.
node.cyclic = true
continue
}
successorNode := &b.blockInfo[successorIndex].tarjan
switch {
case successorNode.lowLink == 0:
// This node has not yet been visisted.
b.strongConnect(successor)
case !successorNode.onStack:
// This node has been visited, but is in a different SCC.
// Ignore it, and do not update lowLink.
continue
}
// Update the lowLink index.
// This always uses the min-of-lowlink instead of using index in the on-stack case.
// This is done for two reasons:
// 1. The lowLink update can be shared between the new-node and on-stack cases.
// 2. The assigned index does not need to be saved - it is only needed for root node detection.
if successorNode.lowLink < node.lowLink {
node.lowLink = successorNode.lowLink
}
}
if node.lowLink == assignedIndex {
// This is a root node.
// Pop the SCC off the stack.
stack := b.tarjanStack
top := stack[len(stack)-1]
stack = stack[:len(stack)-1]
blocks := b.blockInfo
topNode := &blocks[top].tarjan
topNode.onStack = false
if top != uint(blockIndex) {
// The root node is not the only node in the SCC.
// Mark all nodes in this SCC as cyclic.
topNode.cyclic = true
for top != uint(blockIndex) {
top = stack[len(stack)-1]
stack = stack[:len(stack)-1]
topNode = &blocks[top].tarjan
topNode.onStack = false
topNode.cyclic = true
// Search through predecessors.
// Searching backwards means that this is pretty fast when the block is close to the start of the function.
// Defers are often placed near the start of the function.
for _, pred := range block.Preds {
if pred == start {
// cycle found
return true
}
if _, ok := checked[pred]; ok {
// block already checked
continue
}
// add to queue and checked map
queue = append(queue, pred)
checked[pred] = struct{}{}
}
b.tarjanStack = stack
}
}
// tarjanNode holds per-block state for isInLoop and strongConnect.
type tarjanNode struct {
// lowLink is the index of the first visited node that is reachable from this block.
// The lowLink indices are assigned by the SCC search, and do not correspond to b.Index.
// A lowLink of 0 is used as a sentinel to mark a node which has not yet been visited.
lowLink uint
// onStack tracks whether this node is currently on the SCC search stack.
onStack bool
// cyclic indicates whether this block is in a loop.
// If lowLink is 0, strongConnect must be called before reading this field.
cyclic bool
return false
}
// createDefer emits a single defer instruction, to be run when this function
@@ -477,10 +410,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// Put this struct in an allocation.
var alloca llvm.Value
if instr.Block() != b.currentBlock {
panic("block mismatch")
}
if !b.isInLoop() {
if !isInLoop(instr.Block()) {
// This can safely use a stack allocation.
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
} else {
@@ -488,7 +418,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
size := b.targetData.TypeAllocSize(deferredCallType)
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
nilPtr := llvm.ConstNull(b.dataPtrType)
alloca = b.createRuntimeCall(b.allocFunc(), []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
alloca = b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
}
if b.NeedsStackObjects {
b.trackPointer(alloca)
-3
View File
@@ -99,9 +99,6 @@ func typeHasPointers(t llvm.Type) bool {
}
return false
case llvm.ArrayTypeKind:
if t.ArrayLength() == 0 {
return false
}
if typeHasPointers(t.ElementType()) {
return true
}
+3 -3
View File
@@ -38,10 +38,10 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
// provided immediately. For example:
//
// arm.AsmFull(
// "str {value}, [{result}]",
// "str {value}, {result}",
// map[string]interface{}{
// "value": 1,
// "result": uintptr(unsafe.Pointer(&dest)),
// "value": 1
// "result": &dest,
// })
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
+37 -153
View File
@@ -10,7 +10,6 @@ import (
"fmt"
"go/token"
"go/types"
"sort"
"strconv"
"strings"
@@ -18,12 +17,6 @@ import (
"tinygo.org/x/go-llvm"
)
// numMethodHasMethodSet is a flag in bit 15 of the numMethod field (uint16) in
// Named, Pointer, and Struct type descriptors. When set, an inline method set
// is present in the type descriptor. Must match the constant in
// src/internal/reflectlite/type.go.
const numMethodHasMethodSet = 0x8000
// Type kinds for basic types.
// They must match the constants for the Kind type in src/reflect/type.go.
var basicTypes = [...]uint8{
@@ -190,16 +183,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
typeFieldTypes := []*types.Var{
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
}
// Compute the method set value for types that support methods.
var methods []*types.Func
for i := 0; i < ms.Len(); i++ {
methods = append(methods, ms.At(i).Obj().(*types.Func))
}
methodSetType := types.NewStruct([]*types.Var{
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
types.NewVar(token.NoPos, nil, "methods", types.NewArray(types.Typ[types.UnsafePointer], int64(len(methods)))),
}, nil)
methodSetValue := c.getMethodSetValue(methods)
switch typ := typ.(type) {
case *types.Basic:
typeFieldTypes = append(typeFieldTypes,
@@ -216,13 +199,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
)
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
)
case *types.Chan:
@@ -242,11 +218,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
)
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
case *types.Array:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
@@ -271,16 +242,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
)
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
case *types.Interface:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
// TODO: methods
case *types.Signature:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
@@ -326,24 +292,14 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
pkgname = pkg.Name()
}
pkgPathPtr := c.pkgPathPtr(pkgpath)
namedNumMethods := uint64(numMethods)
if namedNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on named type " + name)
}
if len(methods) > 0 {
namedNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), namedNumMethods, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying
pkgPathPtr, // pkgpath pointer
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying
pkgPathPtr, // pkgpath pointer
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
}
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue) // methods
}
typeFields = append(typeFields, c.ctx.ConstString(pkgname+"."+name+"\x00", false)) // name
metabyte |= 1 << 5 // "named" flag
metabyte |= 1 << 5 // "named" flag
case *types.Chan:
var dir reflectChanDir
switch typ.Dir() {
@@ -367,20 +323,10 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
c.getTypeCode(typ.Elem()), // elementType
}
case *types.Pointer:
ptrNumMethods := uint64(numMethods)
if ptrNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on pointer type")
}
if len(methods) > 0 {
ptrNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), ptrNumMethods, false), // numMethods
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(typ.Elem()),
}
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Array:
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
@@ -407,16 +353,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
llvmStructType := c.getLLVMType(typ)
size := c.targetData.TypeStoreSize(llvmStructType)
structNumMethods := uint64(numMethods)
if structNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on struct type")
}
if len(methods) > 0 {
structNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), structNumMethods, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
pkgPathPtr,
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
@@ -468,14 +407,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
}))
}
typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Interface:
typeFields = []llvm.Value{
c.getTypeCode(types.NewPointer(typ)),
methodSetValue,
}
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
// TODO: methods
case *types.Signature:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
// TODO: params, return values, etc
@@ -762,11 +696,17 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
// This type assertion always succeeds, so we can just set commaOk to true.
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
} else {
// Type assert on an interface type with methods.
// Create a call to a declared-but-not-defined function that will
// be lowered by the interface lowering pass into a type-ID
// comparison chain.
commaOk = b.createInterfaceTypeAssert(intf, actualTypeNum)
// Type assert on interface type with methods.
// This is a call to an interface type assert function.
// The interface lowering pass will define this function by filling it
// with a type switch over all concrete types that implement this
// interface, and returning whether it's one of the matched types.
// This is very different from how interface asserts are implemented in
// the main Go compiler, where the runtime checks whether the type
// implements each method of the interface. See:
// https://research.swtch.com/interfaces
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
}
} else {
name, _ := getTypeCodeName(expr.AssertedType)
@@ -797,7 +737,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
prevBlock := b.GetInsertBlock()
okBlock := b.insertBasicBlock("typeassert.ok")
nextBlock := b.insertBasicBlock("typeassert.next")
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
b.CreateCondBr(commaOk, okBlock, nextBlock)
// Retrieve the value from the interface if the type assert was
@@ -843,58 +783,20 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
return strings.Join(methods, "; ")
}
// getMethodSetValue creates the method set struct value for a list of methods.
// The struct contains a length and a sorted array of method signature pointers.
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value {
// Create a sorted list of method signature global names.
type methodRef struct {
name string
value llvm.Value
// getInterfaceImplementsFunc returns a declared function that works as a type
// switch. The interface lowering pass will define this function.
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
s, _ := getTypeCodeName(assertedType.Underlying())
fnName := s + ".$typeassert"
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
c.addStandardDeclaredAttributes(llvmFn)
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
}
var refs []methodRef
for _, method := range methods {
name := method.Name()
if !token.IsExported(name) {
name = method.Pkg().Path() + "." + name
}
s, _ := getTypeCodeName(method.Type())
globalName := "reflect/types.signature:" + name + ":" + s
value := c.mod.NamedGlobal(globalName)
if value.IsNil() {
value = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
value.SetInitializer(llvm.ConstNull(c.ctx.Int8Type()))
value.SetGlobalConstant(true)
value.SetLinkage(llvm.LinkOnceODRLinkage)
value.SetAlignment(1)
if c.Debug {
file := c.getDIFile("<Go type>")
diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{
Name: globalName,
File: file,
Line: 1,
Type: c.getDIType(types.Typ[types.Uint8]),
LocalToUnit: false,
Expr: c.dibuilder.CreateExpression(nil),
AlignInBits: 8,
})
value.AddMetadata(0, diglobal)
}
}
refs = append(refs, methodRef{globalName, value})
}
sort.Slice(refs, func(i, j int) bool {
return refs[i].name < refs[j].name
})
var values []llvm.Value
for _, ref := range refs {
values = append(values, ref.value)
}
return c.ctx.ConstStruct([]llvm.Value{
llvm.ConstInt(c.uintptrType, uint64(len(values)), false),
llvm.ConstArray(c.dataPtrType, values),
}, false)
return llvmFn
}
// getInvokeFunction returns the thunk to call the given interface method. The
@@ -921,24 +823,6 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
return llvmFn
}
// createInterfaceTypeAssert creates a call to a declared-but-not-defined
// $typeassert function for the given interface. This function will be defined
// by the interface lowering pass as a type-ID comparison chain, avoiding the
// need for runtime.typeImplementsMethodSet at compile time.
func (b *builder) createInterfaceTypeAssert(intf *types.Interface, actualType llvm.Value) llvm.Value {
s, _ := getTypeCodeName(intf)
fnName := s + ".$typeassert"
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{b.dataPtrType}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, llvmFnType)
b.addStandardDeclaredAttributes(llvmFn)
methods := b.getMethodsString(intf)
llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("tinygo-methods", methods))
}
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{actualType}, "")
}
// getInterfaceInvokeWrapper returns a wrapper for the given method so it can be
// invoked from an interface. The wrapper takes in a pointer to the underlying
// value, dereferences or unpacks it if necessary, and calls the real method.
+8 -69
View File
@@ -27,8 +27,6 @@ func (b *builder) defineIntrinsicFunction() {
b.createStackSaveImpl()
case name == "runtime.KeepAlive":
b.createKeepAliveImpl()
case name == "machine.keepAliveNoEscape":
b.createMachineKeepAliveImpl()
case strings.HasPrefix(name, "runtime/volatile.Load"):
b.createVolatileLoad()
case strings.HasPrefix(name, "runtime/volatile.Store"):
@@ -50,24 +48,19 @@ func (b *builder) defineIntrinsicFunction() {
// and will otherwise be lowered to regular libc memcpy/memmove calls.
func (b *builder) createMemoryCopyImpl() {
b.createFunctionStart(true)
params := b.fn.Params[0:3]
b.createMemCopy(
b.fn.Name(),
b.getValue(params[0], getPos(b.fn)),
b.getValue(params[1], getPos(b.fn)),
b.getValue(params[2], getPos(b.fn)),
)
b.CreateRetVoid()
}
func (b *builder) createMemCopy(kind string, dst, src, len llvm.Value) llvm.Value {
fnName := "llvm." + kind + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType, b.dataPtrType, b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{dst, src, len, llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
var params []llvm.Value
for _, param := range b.fn.Params {
params = append(params, b.getValue(param, getPos(b.fn)))
}
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
b.CreateRetVoid()
}
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
@@ -128,43 +121,6 @@ func (b *builder) createKeepAliveImpl() {
b.CreateRetVoid()
}
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
// currently only supports pointer types.
func (b *builder) createAbiEscapeImpl() {
b.createFunctionStart(true)
// The first parameter is assumed to be a pointer. This is checked at the
// call site of createAbiEscapeImpl.
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
// Create an equivalent of the following C code, which is basically just a
// nop but ensures the pointerValue is kept alive:
//
// __asm__ __volatile__("" : : "r"(pointerValue))
//
// It should be portable to basically everything as the "r" register type
// exists basically everywhere.
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
b.CreateRet(result)
}
// Implement machine.keepAliveNoEscape, which makes sure the compiler keeps the
// pointer parameter alive until this point (for GC).
func (b *builder) createMachineKeepAliveImpl() {
b.createFunctionStart(true)
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
// See createKeepAliveImpl for details.
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
b.CreateRetVoid()
}
var mathToLLVMMapping = map[string]string{
"math.Ceil": "llvm.ceil.f64",
"math.Exp": "llvm.exp.f64",
@@ -208,23 +164,6 @@ func (b *builder) defineMathOp() {
b.CreateRet(result)
}
func (b *builder) defineCryptoIntrinsic() bool {
if b.fn.Pkg.Pkg.Path() != "crypto/internal/constanttime" {
return false
}
switch b.fn.Name() {
case "boolToUint8":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
result := b.CreateZExt(param, b.ctx.Int8Type(), "")
b.CreateRet(result)
return true
}
return false
}
// Implement most math/bits functions.
//
// This implements all the functions that operate on bits. It does not yet
+96 -94
View File
@@ -1,10 +1,10 @@
package compiler
import (
"encoding/binary"
"fmt"
"go/token"
"go/types"
"math/big"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
@@ -129,9 +129,11 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
// Packed data is bigger than a pointer, so allocate it on the heap.
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
align := b.targetData.ABITypeAlignment(packedType)
packedAlloc := b.createRuntimeCall(b.allocFunc(), []llvm.Value{
alloc := b.mod.NamedFunction("runtime.alloc")
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
sizeValue,
llvm.ConstNull(b.dataPtrType),
llvm.Undef(b.dataPtrType), // unused context parameter
}, "")
packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
if b.NeedsStackObjects {
@@ -229,12 +231,6 @@ func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType l
//
// For details on what's in this value, see src/runtime/gc_precise.go.
func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Value {
if !typeHasPointers(t) {
// There are no pointers in this type, so we can simplify the layout.
layout := (uint64(1) << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
// Use the element type for arrays. This works even for nested arrays.
for {
kind := t.TypeKind()
@@ -252,29 +248,54 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
break
}
// Create the pointer bitmap.
// Do a few checks to see whether we need to generate any object layout
// information at all.
objectSizeBytes := c.targetData.TypeAllocSize(t)
pointerAlignment := uint64(c.targetData.PrefTypeAlignment(c.dataPtrType))
bitmapLen := objectSizeBytes / pointerAlignment
bitmapBytes := (bitmapLen + 7) / 8
bitmap := make([]byte, bitmapBytes, max(bitmapBytes, 8))
c.buildPointerBitmap(bitmap, pointerAlignment, pos, t, 0)
// Try to encode the layout inline.
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
pointerBits := pointerSize * 8
if bitmapLen < pointerBits {
rawMask := binary.LittleEndian.Uint64(bitmap[0:8])
layout := rawMask*pointerBits + bitmapLen
layout <<= 1
layout |= 1
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
if objectSizeBytes < pointerSize {
// Too small to contain a pointer.
layout := (uint64(1) << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
bitmap := c.getPointerBitmap(t, pos)
if bitmap.BitLen() == 0 {
// There are no pointers in this type, so we can simplify the layout.
// TODO: this can be done in many other cases, e.g. when allocating an
// array (like [4][]byte, which repeats a slice 4 times).
layout := (uint64(1) << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
if objectSizeBytes%uint64(pointerAlignment) != 0 {
// This shouldn't happen except for packed structs, which aren't
// currently used.
c.addError(pos, "internal error: unexpected object size for object with pointer field")
return llvm.ConstNull(c.dataPtrType)
}
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
// Check if the layout fits.
layout &= 1<<pointerBits - 1
if (layout>>1)/pointerBits == rawMask {
// No set bits were shifted off.
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
pointerBits := pointerSize * 8
var sizeFieldBits uint64
switch pointerBits {
case 16:
sizeFieldBits = 4
case 32:
sizeFieldBits = 5
case 64:
sizeFieldBits = 6
default:
panic("unknown pointer size")
}
layoutFieldBits := pointerBits - 1 - sizeFieldBits
// Try to emit the value as an inline integer. This is possible in most
// cases.
if objectSizeWords < layoutFieldBits {
// If it can be stored directly in the pointer value, do so.
// The runtime knows that if the least significant bit of the pointer is
// set, the pointer contains the value itself.
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
// Unfortunately, the object layout is too big to fit in a pointer-sized
@@ -282,24 +303,25 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
// Try first whether the global already exists. All objects with a
// particular name have the same type, so this is possible.
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", bitmapLen, (bitmapLen+15)/16, bitmap)
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
global := c.mod.NamedGlobal(globalName)
if !global.IsNil() {
return global
}
// Create the global initializer.
bitmapByteValues := make([]llvm.Value, bitmapBytes)
i8 := c.ctx.Int8Type()
for i, b := range bitmap {
bitmapByteValues[i] = llvm.ConstInt(i8, uint64(b), false)
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
bitmap.FillBytes(bitmapBytes)
reverseBytes(bitmapBytes) // big-endian to little-endian
var bitmapByteValues []llvm.Value
for _, b := range bitmapBytes {
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
}
initializer := c.ctx.ConstStruct([]llvm.Value{
llvm.ConstInt(c.uintptrType, bitmapLen, false),
llvm.ConstArray(i8, bitmapByteValues),
llvm.ConstInt(c.uintptrType, objectSizeWords, false),
llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
}, false)
// Create the actual global.
global = llvm.AddGlobal(c.mod, initializer.Type(), globalName)
global.SetInitializer(initializer)
global.SetUnnamedAddr(true)
@@ -307,7 +329,6 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
global.SetLinkage(llvm.LinkOnceODRLinkage)
if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 {
// AVR doesn't have alignment by default.
// The lowest bit must be unset to distinguish this from an inline layout.
global.SetAlignment(2)
}
if c.Debug && pos != token.NoPos {
@@ -339,71 +360,52 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
return global
}
// buildPointerBitmap scans the given LLVM type for pointers and sets bits in a
// bitmap at the word offset that contains a pointer. This scan is recursive.
func (c *compilerContext) buildPointerBitmap(
dst []byte,
ptrAlign uint64,
pos token.Pos,
t llvm.Type,
offset uint64,
) {
switch t.TypeKind() {
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
// bigint at the word offset that contains a pointer. This scan is recursive.
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
switch typ.TypeKind() {
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
// These types do not contain pointers.
return big.NewInt(0)
case llvm.PointerTypeKind:
// Set the corresponding position in the bitmap.
dst[offset/8] |= 1 << (offset % 8)
return big.NewInt(1)
case llvm.StructTypeKind:
// Recurse over struct elements.
for i, et := range t.StructElementTypes() {
eo := c.targetData.ElementOffset(t, i)
if eo%uint64(ptrAlign) != 0 {
if typeHasPointers(et) {
// This error will let the compilation fail, but by continuing
// the error can still easily be shown.
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
}
ptrs := big.NewInt(0)
for i, subtyp := range typ.StructElementTypes() {
subptrs := c.getPointerBitmap(subtyp, pos)
if subptrs.BitLen() == 0 {
continue
}
c.buildPointerBitmap(
dst,
ptrAlign,
pos,
et,
offset+(eo/ptrAlign),
)
}
case llvm.ArrayTypeKind:
// Recurse over array elements.
len := t.ArrayLength()
if len <= 0 {
return
}
et := t.ElementType()
elementSize := c.targetData.TypeAllocSize(et)
if elementSize%ptrAlign != 0 {
if typeHasPointers(et) {
// This error will let the compilation fail (but continues so that
// other errors can be shown).
c.addError(pos, "internal error: allocated array contains unaligned pointer")
offset := c.targetData.ElementOffset(typ, i)
if offset%uint64(alignment) != 0 {
// This error will let the compilation fail, but by continuing
// the error can still easily be shown.
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
continue
}
return
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
elementSize /= ptrAlign
for i := 0; i < len; i++ {
c.buildPointerBitmap(
dst,
ptrAlign,
pos,
et,
offset+uint64(i)*elementSize,
)
return ptrs
case llvm.ArrayTypeKind:
subtyp := typ.ElementType()
subptrs := c.getPointerBitmap(subtyp, pos)
ptrs := big.NewInt(0)
if subptrs.BitLen() == 0 {
return ptrs
}
elementSize := c.targetData.TypeAllocSize(subtyp)
if elementSize%uint64(alignment) != 0 {
// This error will let the compilation fail (but continues so that
// other errors can be shown).
c.addError(pos, "internal error: allocated array contains unaligned pointer")
return ptrs
}
for i := 0; i < typ.ArrayLength(); i++ {
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
return ptrs
default:
// Should not happen.
panic("unknown LLVM type")
+1 -1
View File
@@ -218,7 +218,7 @@ func Version() int {
return major
}
// ByteOrder returns the byte order for the given target triple. Most targets are little
// Return the byte order for the given target triple. Most targets are little
// endian, but for example MIPS can be big-endian.
func ByteOrder(target string) binary.ByteOrder {
if strings.HasPrefix(target, "mips-") {
+154 -444
View File
@@ -3,28 +3,42 @@ package compiler
// This file emits the correct map intrinsics for map operations.
import (
"fmt"
"go/token"
"go/types"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
)
const hashArrayUnrollLimit = 4
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
// initializing an appropriately sized object.
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
mapType := expr.Type().Underlying().(*types.Map)
keyType := mapType.Key().Underlying()
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
llvmKeyType := b.getLLVMType(keyType)
var llvmKeyType llvm.Type
var alg uint64
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// String keys.
llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmString)
} else if hashmapIsBinaryKey(keyType) {
// Trivially comparable keys.
llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmBinary)
} else {
// All other keys. Implemented as map[interface{}]valueType for ease of
// implementation.
llvmKeyType = b.getLLVMRuntimeType("_interface")
alg = uint64(tinygo.HashmapAlgorithmInterface)
}
keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType)
llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil {
sizeHint = b.getValue(expr.Reserve, getPos(expr))
var err error
@@ -33,42 +47,10 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
return llvm.Value{}, err
}
}
// Resolve hash and equal functions for this key type. For string and
// binary key types, reference the corresponding runtime functions
// directly. For composite types, generate type-specific functions.
var hashFn, equalFn llvm.Value
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
hashFn = b.getRuntimeFunctionValue("hashmapStringPtrHash", hashmapKeyHashSignature())
equalFn = b.getRuntimeFunctionValue("hashmapStringEqual", hashmapKeyEqualSignature())
} else if hashmapIsBinaryKey(keyType) {
hashFn = b.getRuntimeFunctionValue("hash32", hashmapKeyHashSignature())
equalFn = b.getRuntimeFunctionValue("memequal", hashmapKeyEqualSignature())
} else {
fn := b.getOrGenerateKeyHashFunc(keyType)
hashFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyHashSignature())
fn = b.getOrGenerateKeyEqualFunc(keyType)
equalFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyEqualSignature())
}
hashmap := b.createRuntimeCall("hashmapMakeGeneric", []llvm.Value{
llvmKeySize, llvmValueSize, sizeHint,
hashFn, equalFn,
}, "")
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
return hashmap, nil
}
// getRuntimeFunctionValue returns a TinyGo function value (with nil context)
// for the named runtime function.
func (b *builder) getRuntimeFunctionValue(name string, sig *types.Signature) llvm.Value {
member := b.program.ImportedPackage("runtime").Members[name]
if member == nil {
panic("unknown runtime function: " + name)
}
_, llvmFn := b.getFunction(member.(*ssa.Function))
return b.createFuncValue(llvmFn, llvm.ConstNull(b.dataPtrType), sig)
}
// createMapLookup returns the value in a map. It calls a runtime function
// depending on the map key type to load the map value and its comma-ok value.
func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
@@ -90,23 +72,32 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
// Do the lookup. How it is done depends on the key type.
var commaOkValue llvm.Value
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
params := []llvm.Value{m, key, mapValueAlloca, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
} else {
// Key stored at actual type: either binary-comparable or with
// compiler-generated hash/equal.
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
// Store the key in an alloca, in the entry block to avoid dynamic stack
// growth.
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, mapKeyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
// Fetch the value from the hashmap.
params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize}
fnName := "hashmapBinaryGet"
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericGet"
}
commaOkValue = b.createRuntimeCall(fnName, params, "")
commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
} else {
// Not trivially comparable using memcmp. Make it an interface instead.
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface now.
itfKey = b.createMakeInterface(key, origKeyType, pos)
}
params := []llvm.Value{m, itfKey, mapValueAlloca, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
}
// Load the resulting value from the hashmap. The value is set to the zero
@@ -129,22 +120,29 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
b.CreateStore(value, valueAlloca)
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
params := []llvm.Value{m, key, valueAlloca}
b.createRuntimeCall("hashmapStringSet", params, "")
} else {
// Key stored at actual type.
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca)
fnName := "hashmapBinarySet"
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericSet"
}
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
params := []llvm.Value{m, keyAlloca, valueAlloca}
b.createRuntimeCall(fnName, params, "")
b.createRuntimeCall("hashmapBinarySet", params, "")
b.emitLifetimeEnd(keyAlloca, keySize)
} else {
// Key is not trivially comparable, so compare it as an interface instead.
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface first.
itfKey = b.createMakeInterface(key, origKeyType, pos)
}
params := []llvm.Value{m, itfKey, valueAlloca}
b.createRuntimeCall("hashmapInterfaceSet", params, "")
}
b.emitLifetimeEnd(valueAlloca, valueSize)
}
@@ -152,24 +150,32 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
// createMapDelete deletes a key from a map by calling the appropriate runtime
// function. It is the implementation of the Go delete() builtin.
func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
params := []llvm.Value{m, key}
b.createRuntimeCall("hashmapStringDelete", params, "")
return nil
} else {
// Key stored at actual type.
} else if hashmapIsBinaryKey(keyType) {
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca)
fnName := "hashmapBinaryDelete"
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericDelete"
}
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
params := []llvm.Value{m, keyAlloca}
b.createRuntimeCall(fnName, params, "")
b.createRuntimeCall("hashmapBinaryDelete", params, "")
b.emitLifetimeEnd(keyAlloca, keySize)
return nil
} else {
// Key is not trivially comparable, so compare it as an interface
// instead.
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface first.
itfKey = b.createMakeInterface(key, origKeyType, pos)
}
params := []llvm.Value{m, itfKey}
b.createRuntimeCall("hashmapInterfaceDelete", params, "")
return nil
}
}
@@ -189,15 +195,42 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
llvmKeyType := b.getLLVMType(keyType)
llvmValueType := b.getLLVMType(valueType)
// All key types are now stored at their declared type (no interface wrapping).
// There is a special case in which keys are stored as an interface value
// instead of the value they normally are. This happens for non-trivially
// comparable types such as float32 or some structs.
isKeyStoredAsInterface := false
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
} else {
// The key is stored as an interface value, and may or may not be an
// interface type (for example, float32 keys are stored as an interface
// value).
if _, ok := keyType.Underlying().(*types.Interface); !ok {
isKeyStoredAsInterface = true
}
}
// Determine the type of the key as stored in the map.
llvmStoredKeyType := llvmKeyType
if isKeyStoredAsInterface {
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
}
// Extract the key and value from the map.
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next")
mapKey := b.CreateLoad(llvmKeyType, mapKeyAlloca, "")
mapKey := b.CreateLoad(llvmStoredKeyType, mapKeyAlloca, "")
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
if isKeyStoredAsInterface {
// The key is stored as an interface but it isn't of interface type.
// Extract the underlying value.
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
}
// End the lifetimes of the allocas, because we're done with them.
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
b.emitLifetimeEnd(mapValueAlloca, mapValueSize)
@@ -217,9 +250,17 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
func hashmapIsBinaryKey(keyType types.Type) bool {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 || keyType.Kind() == types.UnsafePointer
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
case *types.Pointer:
return true
case *types.Struct:
for i := 0; i < keyType.NumFields(); i++ {
fieldType := keyType.Field(i).Type().Underlying()
if !hashmapIsBinaryKey(fieldType) {
return false
}
}
return true
case *types.Array:
return hashmapIsBinaryKey(keyType.Elem())
default:
@@ -227,399 +268,68 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
}
}
// hashmapKeyHashSignature returns the Go type signature for hashmap key hash
// functions: func(key unsafe.Pointer, size, seed uintptr) uint32
func hashmapKeyHashSignature() *types.Signature {
return types.NewSignatureType(nil, nil, nil,
types.NewTuple(
types.NewVar(token.NoPos, nil, "key", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uintptr]),
types.NewVar(token.NoPos, nil, "seed", types.Typ[types.Uintptr]),
),
types.NewTuple(
types.NewVar(token.NoPos, nil, "", types.Typ[types.Uint32]),
),
false,
)
}
func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
// We know that hashmapIsBinaryKey is true, so we only have to handle those types that can show up there.
// To zero all undefined bytes, we iterate over all the fields in the type. For each element, compute the
// offset of that element. If it's Basic type, there are no internal padding bytes. For compound types, we recurse to ensure
// we handle nested types. Next, we determine if there are any padding bytes before the next
// element and zero those as well.
// hashmapKeyEqualSignature returns the Go type signature for hashmap key equal
// functions: func(x, y unsafe.Pointer, n uintptr) bool
func hashmapKeyEqualSignature() *types.Signature {
return types.NewSignatureType(nil, nil, nil,
types.NewTuple(
types.NewVar(token.NoPos, nil, "x", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "y", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "n", types.Typ[types.Uintptr]),
),
types.NewTuple(
types.NewVar(token.NoPos, nil, "", types.Typ[types.Bool]),
),
false,
)
}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
// hashmapKeyFuncName returns a canonical name for a generated hash or equal
// function based on the key type's underlying structure. Named types are
// replaced with their underlying types so that structurally identical key
// types (e.g., struct{i1; str1} and struct{i2; str2} where both i1, i2 are
// int and str1, str2 are string) share the same generated function.
func hashmapKeyFuncName(prefix string, keyType types.Type) string {
return prefix + "." + hashmapCanonicalTypeName(keyType)
}
switch llvmType.TypeKind() {
case llvm.IntegerTypeKind:
// no padding bytes
return nil
case llvm.PointerTypeKind:
// mo padding bytes
return nil
case llvm.ArrayTypeKind:
llvmArrayType := llvmType
llvmElemType := llvmType.ElementType()
// hashmapCanonicalTypeName returns a string representation of the hash/equal
// operations needed for a type, stripping named types where the operation does
// not depend on the name. Pointer and channel names do not include the element
// type because their hash/equal operations only use the pointer word.
func hashmapCanonicalTypeName(t types.Type) string {
switch t := t.Underlying().(type) {
case *types.Basic:
return t.Name()
case *types.Pointer:
return "*"
case *types.Chan:
switch t.Dir() {
case types.SendRecv:
return "chan"
case types.SendOnly:
return "chan<-"
case types.RecvOnly:
return "<-chan"
for i := 0; i < llvmArrayType.ArrayLength(); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
elemPtr := b.CreateInBoundsGEP(llvmArrayType, ptr, []llvm.Value{zero, idx}, "")
// zero any padding bytes in this element
b.zeroUndefBytes(llvmElemType, elemPtr)
}
case *types.Interface:
if t.NumMethods() == 0 {
return "interface{}"
}
return t.String()
case *types.Struct:
s := "struct{"
for i := 0; i < t.NumFields(); i++ {
if i > 0 {
s += "; "
}
s += hashmapCanonicalTypeName(t.Field(i).Type())
}
return s + "}"
case *types.Array:
return fmt.Sprintf("[%d]%s", t.Len(), hashmapCanonicalTypeName(t.Elem()))
}
return t.String()
}
// getOrGenerateKeyHashFunc returns an LLVM function that computes the hash
// of a key of the given type. The function is generated on first call and
// cached in the module.
func (b *builder) getOrGenerateKeyHashFunc(keyType types.Type) llvm.Value {
name := hashmapKeyFuncName("hashmapKeyHash", keyType)
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
return fn
}
case llvm.StructTypeKind:
llvmStructType := llvmType
numFields := llvmStructType.StructElementTypesCount()
llvmElementTypes := llvmStructType.StructElementTypes()
// Create the LLVM function type:
// (key ptr, size uintptr, seed uintptr, context ptr) -> i32
fnType := llvm.FunctionType(b.ctx.Int32Type(), []llvm.Type{
b.dataPtrType, b.uintptrType, b.uintptrType, b.dataPtrType,
}, false)
fn := llvm.AddFunction(b.mod, name, fnType)
fn.SetLinkage(llvm.LinkOnceODRLinkage)
fn.SetUnnamedAddr(true)
b.addStandardAttributes(fn)
// Generate the function body.
savedBlock := b.GetInsertBlock()
defer b.SetInsertPointAtEnd(savedBlock)
entry := b.ctx.AddBasicBlock(fn, "entry")
b.SetInsertPointAtEnd(entry)
keyPtr := fn.Param(0)
seed := fn.Param(2)
llvmKeyType := b.getLLVMType(keyType)
hash := b.generateKeyHash(keyType, llvmKeyType, keyPtr, seed)
b.CreateRet(hash)
return fn
}
// getOrGenerateKeyEqualFunc returns an LLVM function that compares two keys
// of the given type for equality. The function is generated on first call
// and cached in the module.
func (b *builder) getOrGenerateKeyEqualFunc(keyType types.Type) llvm.Value {
name := hashmapKeyFuncName("hashmapKeyEqual", keyType)
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
return fn
}
// Create the LLVM function type:
// (x ptr, y ptr, n uintptr, context ptr) -> i1
fnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{
b.dataPtrType, b.dataPtrType, b.uintptrType, b.dataPtrType,
}, false)
fn := llvm.AddFunction(b.mod, name, fnType)
fn.SetLinkage(llvm.LinkOnceODRLinkage)
fn.SetUnnamedAddr(true)
b.addStandardAttributes(fn)
// Generate the function body.
savedBlock := b.GetInsertBlock()
defer b.SetInsertPointAtEnd(savedBlock)
entry := b.ctx.AddBasicBlock(fn, "entry")
b.SetInsertPointAtEnd(entry)
xPtr := fn.Param(0)
yPtr := fn.Param(1)
llvmKeyType := b.getLLVMType(keyType)
result := b.generateKeyEqual(keyType, llvmKeyType, xPtr, yPtr, fn)
b.CreateRet(result)
return fn
}
// generateKeyHash generates IR that hashes a key value. Returns the i32 hash.
func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, keyPtr llvm.Value, seed llvm.Value) llvm.Value {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
if keyType.Info()&types.IsString != 0 {
// Hash the string contents. The size parameter is unused by
// hashmapStringPtrHash (it dereferences the string header to
// get the actual length), but we pass it for signature
// consistency with other hash functions.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapStringPtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
}
if keyType.Info()&types.IsFloat != 0 {
// Float hash: normalizes -0 to +0 before hashing.
if keyType.Kind() == types.Float32 {
return b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{keyPtr, seed}, "hash")
}
return b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{keyPtr, seed}, "hash")
}
if keyType.Info()&types.IsComplex != 0 {
// Complex hash: hash real and imaginary parts as floats.
if keyType.Kind() == types.Complex64 {
realPtr := keyPtr
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
llvm.ConstInt(b.uintptrType, 4, false),
}, "")
realHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{realPtr, seed}, "hash.real")
imagHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
return b.CreateXor(realHash, imagHash, "")
}
realPtr := keyPtr
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
llvm.ConstInt(b.uintptrType, 8, false),
}, "")
realHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{realPtr, seed}, "hash.real")
imagHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
return b.CreateXor(realHash, imagHash, "")
}
// Integer/boolean: hash the raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Pointer, *types.Chan:
// Pointers and channels: hash as raw pointer-sized bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Interface:
// Interface: use runtime reflection-based hash.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Struct:
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < keyType.NumFields(); i++ {
if keyType.Field(i).Name() == "_" {
continue // blank fields are ignored in Go equality
}
fieldType := keyType.Field(i).Type()
llvmFieldType := b.getLLVMType(fieldType)
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
continue // skip zero-sized fields
}
for i := 0; i < numFields; i++ {
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
hash = b.CreateXor(hash, fieldHash, "")
}
return hash
case *types.Array:
elemType := keyType.Elem()
llvmElemType := b.getLLVMType(elemType)
arrayLen := keyType.Len()
if hashmapIsBinaryKey(elemType) {
// All elements are binary-comparable; hash the entire array as raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
}
if arrayLen == 0 {
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
}
if arrayLen <= hashArrayUnrollLimit {
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < int(arrayLen); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
hash = b.CreateXor(hash, elemHash, "")
}
return hash
}
initHash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
elemPtr := b.CreateInBoundsGEP(llvmStructType, ptr, []llvm.Value{zero, idx}, "")
loopEntry := b.GetInsertBlock()
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.body")
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.done")
// zero any padding bytes in this field
llvmElemType := llvmElementTypes[i]
b.zeroUndefBytes(llvmElemType, elemPtr)
b.CreateBr(loopBody)
b.SetInsertPointAtEnd(loopBody)
// zero any padding bytes before the next field, if any
offset := b.targetData.ElementOffset(llvmStructType, i)
storeSize := b.targetData.TypeStoreSize(llvmElemType)
fieldEndOffset := offset + storeSize
phiI := b.CreatePHI(b.uintptrType, "i")
phiHash := b.CreatePHI(b.ctx.Int32Type(), "hash.acc")
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
newHash := b.CreateXor(phiHash, elemHash, "")
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
b.CreateCondBr(cond, loopBody, loopDone)
bodyEnd := b.GetInsertBlock()
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
[]llvm.BasicBlock{loopEntry, bodyEnd})
phiHash.AddIncoming([]llvm.Value{initHash, newHash},
[]llvm.BasicBlock{loopEntry, bodyEnd})
b.SetInsertPointAtEnd(loopDone)
return newHash
default:
panic(fmt.Sprintf("unhandled key type for hash generation: %T", keyType))
}
}
// generateKeyEqual generates IR that compares two key values for equality.
// Returns an i1 result.
func (b *builder) generateKeyEqual(keyType types.Type, llvmKeyType llvm.Type, xPtr, yPtr llvm.Value, fn llvm.Value) llvm.Value {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
if keyType.Info()&types.IsString != 0 {
// Compare strings: load both string headers and compare.
xStr := b.CreateLoad(llvmKeyType, xPtr, "x.str")
yStr := b.CreateLoad(llvmKeyType, yPtr, "y.str")
return b.createRuntimeCall("stringEqual", []llvm.Value{xStr, yStr}, "eq")
}
if keyType.Info()&types.IsFloat != 0 {
// Float equality: fcmp oeq handles -0==+0 (true) and NaN==NaN (false).
xVal := b.CreateLoad(llvmKeyType, xPtr, "x.float")
yVal := b.CreateLoad(llvmKeyType, yPtr, "y.float")
return b.CreateFCmp(llvm.FloatOEQ, xVal, yVal, "eq")
}
if keyType.Info()&types.IsComplex != 0 {
// Complex equality: both real and imaginary parts must be equal.
var floatType llvm.Type
if keyType.Kind() == types.Complex64 {
floatType = b.ctx.FloatType()
var nextOffset uint64
if i < numFields-1 {
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
} else {
floatType = b.ctx.DoubleType()
// Last field? Next offset is the total size of the allocate struct.
nextOffset = b.targetData.TypeAllocSize(llvmStructType)
}
floatSize := b.targetData.TypeAllocSize(floatType)
imagOffset := llvm.ConstInt(b.uintptrType, floatSize, false)
// Real parts
xReal := b.CreateLoad(floatType, xPtr, "x.real")
yReal := b.CreateLoad(floatType, yPtr, "y.real")
realEq := b.CreateFCmp(llvm.FloatOEQ, xReal, yReal, "eq.real")
// Imaginary parts
xImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), xPtr, []llvm.Value{imagOffset}, "")
yImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), yPtr, []llvm.Value{imagOffset}, "")
xImag := b.CreateLoad(floatType, xImagPtr, "x.imag")
yImag := b.CreateLoad(floatType, yImagPtr, "y.imag")
imagEq := b.CreateFCmp(llvm.FloatOEQ, xImag, yImag, "eq.imag")
return b.CreateAnd(realEq, imagEq, "")
}
// Integer/boolean: compare raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Pointer, *types.Chan:
// Pointers and channels: compare as raw pointer-sized bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Interface:
// Interface: use runtime interface equality.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapInterfaceEqual", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Struct:
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false) // start with true
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < keyType.NumFields(); i++ {
if keyType.Field(i).Name() == "_" {
continue // blank fields are ignored in Go equality
if fieldEndOffset != nextOffset {
n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), elemPtr, []llvm.Value{llvmStoreSize}, "")
b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
}
fieldType := keyType.Field(i).Type()
llvmFieldType := b.getLLVMType(fieldType)
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
continue // skip zero-sized fields
}
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
xFieldPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
yFieldPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
fieldEq := b.generateKeyEqual(fieldType, llvmFieldType, xFieldPtr, yFieldPtr, fn)
result = b.CreateAnd(result, fieldEq, "")
}
return result
case *types.Array:
elemType := keyType.Elem()
llvmElemType := b.getLLVMType(elemType)
arrayLen := keyType.Len()
if hashmapIsBinaryKey(elemType) {
// All elements are binary-comparable; compare the entire array.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
}
if arrayLen == 0 {
return llvm.ConstInt(b.ctx.Int1Type(), 1, false)
}
if arrayLen <= hashArrayUnrollLimit {
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < int(arrayLen); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
result = b.CreateAnd(result, elemEq, "")
}
return result
}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
loopEntry := b.GetInsertBlock()
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.body")
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.done")
b.CreateBr(loopBody)
b.SetInsertPointAtEnd(loopBody)
phiI := b.CreatePHI(b.uintptrType, "i")
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, phiI}, "")
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, phiI}, "")
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
atEnd := b.CreateICmp(llvm.IntUGE, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
exitLoop := b.CreateOr(atEnd, b.CreateNot(elemEq, ""), "")
b.CreateCondBr(exitLoop, loopDone, loopBody)
bodyEnd := b.GetInsertBlock()
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
[]llvm.BasicBlock{loopEntry, bodyEnd})
b.SetInsertPointAtEnd(loopDone)
return elemEq
default:
panic(fmt.Sprintf("unhandled key type for equal generation: %T", keyType))
}
return nil
}
+12 -70
View File
@@ -34,7 +34,6 @@ type functionInfo struct {
interrupt bool // go:interrupt
nobounds bool // go:nobounds
noescape bool // go:noescape
noheap bool // go:noheap
variadic bool // go:variadic (CGo only)
inline inlineType // go:inline
}
@@ -143,11 +142,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
llvmFn.AddAttributeAtIndex(i+1, nocapture)
}
if paramInfo.flags&paramIsReadonly != 0 && paramInfo.llvmType.TypeKind() == llvm.PointerTypeKind {
// Readonly pointer parameters (like strings) benefit from being marked as readonly.
readonly := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)
llvmFn.AddAttributeAtIndex(i+1, readonly)
}
}
// Set a number of function or parameter attributes, depending on the
@@ -160,9 +154,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
case "internal/abi.NoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "machine.keepAliveNoEscape", "machine.unsafeNoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.alloc", "runtime.alloc_noheap":
case "runtime.alloc":
// Tell the optimizer that runtime.alloc is an allocator, meaning that it
// returns values that are never null and never alias to an existing value.
for _, attrName := range []string{"noalias", "nonnull"} {
@@ -185,37 +177,18 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// be modified.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.sliceCopy":
// Copying a slice won't capture any of the parameters.
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("writeonly"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.stringFromBytes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.stringFromRunes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.hashmapSet":
// The key (param 2) and value (param 3) pointers are only read via
// memcpy/hash/equal and are never captured. The indirect calls
// through m.keyHash and m.keyEqual function pointers prevent LLVM's
// functionattrs pass from inferring this automatically.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGet":
// The key (param 2) is read-only and never captured.
// The value (param 3) is written to (receives the result) but never captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapDelete":
// The key (param 2) is read-only and never captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericSet":
// Same as hashmapBinarySet: key (param 2) and value (param 3) are
// not captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericGet":
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericDelete":
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer
@@ -280,23 +253,6 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
// The exception is the package initializer, which does appear in the
// *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 origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
// This is a special implementation or internal/abi.Escape, which
// can only really be implemented in the compiler.
// For simplicity we'll only implement pointer parameters for now.
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
irbuilder := c.ctx.NewBuilder()
defer irbuilder.Dispose()
b := newBuilder(c, irbuilder, fn)
b.createAbiEscapeImpl()
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
llvmFn.SetUnnamedAddr(true)
}
// If the parameter is not of a pointer type, it will be left
// unimplemented. This will result in a linker error if the function
// is really called, making it clear it needs to be implemented.
return
}
if len(fn.Blocks) == 0 {
c.addError(fn.Pos(), "missing function body")
return
@@ -477,9 +433,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
if len(f.Blocks) == 0 {
info.noescape = true
}
case "//go:noheap":
// Ensure this function does not allocate on the heap.
info.noheap = true
case "//go:variadic":
// The //go:variadic pragma is emitted by the CGo preprocessing
// pass for C variadic functions. This includes both explicit
@@ -569,7 +522,7 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
}
for i := 0; i < typ.NumFields(); i++ {
ftyp := typ.Field(i).Type()
if types.Unalias(ftyp).String() == "structs.HostLayout" {
if ftyp.String() == "structs.HostLayout" {
hasHostLayout = true
continue
}
@@ -660,7 +613,7 @@ func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
// linkName is equal to .RelString(nil) on a global and extern is false, but for
// some symbols this is different (due to //go:extern for example).
type globalInfo struct {
linkName string // go:extern, go:linkname
linkName string // go:extern
extern bool // go:extern
align int // go:align
section string // go:section
@@ -745,14 +698,14 @@ func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
// Check for //go: pragmas, which may change the link name (among others).
doc := c.astComments[info.linkName]
if doc != nil {
info.parsePragmas(doc, c, g)
info.parsePragmas(doc)
}
return info
}
// Parse //go: pragma comments from the source. In particular, it parses the
// //go:extern and //go:linkname pragmas on globals.
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext, g *ssa.Global) {
// //go:extern pragma on globals.
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
for _, comment := range doc.List {
if !strings.HasPrefix(comment.Text, "//go:") {
continue
@@ -773,17 +726,6 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext,
if len(parts) == 2 {
info.section = parts[1]
}
case "//go:linkname":
if len(parts) != 3 || parts[1] != g.Name() {
continue
}
// Only enable go:linkname when the package imports "unsafe".
// This is a slightly looser requirement than what gc uses: gc
// requires the file to import "unsafe", not the package as a
// whole.
if hasUnsafeImport(g.Pkg.Pkg) {
info.linkName = parts[2]
}
}
}
}
-132
View File
@@ -74,14 +74,6 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
return b.CreateCall(fnType, target, args, ""), nil
case b.GOARCH == "arm" && b.GOOS == "linux":
if arch := b.archFamily(); arch != "arm" {
// Some targets pretend to be linux/arm for compatibility but aren't
// actually such a system. Make sure we emit an error instead of
// creating inline assembly that will fail to compile.
// See: https://github.com/tinygo-org/tinygo/issues/4959
return llvm.Value{}, b.makeError(call.Pos(), "system calls are not supported: target emulates a linux/arm system on "+arch)
}
// Implement the EABI system call convention for Linux.
// Source: syscall(2) man page.
args := []llvm.Value{}
@@ -349,130 +341,6 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
}
}
// createSyscalln emits instructions for the syscall.syscalln function on
// Windows. This handles the variadic calling convention used in Go 1.26+:
//
// func syscalln(fn, n uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
//
// The function generates a switch on n to dispatch to the correct fixed-argument
// function pointer call with SetLastError(0)/GetLastError() wrapping.
func (b *builder) createSyscalln(call *ssa.CallCommon) (llvm.Value, error) {
const maxArgs = 18 // Windows syscalls support up to 18 args
isI386 := strings.HasPrefix(b.Triple, "i386-")
// Get the function pointer (call.Args[0]) and n (call.Args[1]).
fn := b.getValue(call.Args[0], getPos(call))
fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
n := b.getValue(call.Args[1], getPos(call))
// Get the variadic args slice (call.Args[2]).
// In SSA, the variadic slice is the third argument.
var argsPtr llvm.Value
if len(call.Args) > 2 {
argsSlice := b.getValue(call.Args[2], getPos(call))
argsPtr = b.CreateExtractValue(argsSlice, 0, "args.data")
} else {
argsPtr = llvm.ConstNull(b.dataPtrType)
}
// Prepare SetLastError and GetLastError.
setLastError := b.mod.NamedFunction("SetLastError")
if setLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
if isI386 {
setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
getLastError := b.mod.NamedFunction("GetLastError")
if getLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
if isI386 {
getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
retType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false)
// Create the merge block where all cases converge.
mergeBB := b.insertBasicBlock("syscalln.merge")
// Create the default (panic) block.
panicBB := b.insertBasicBlock("syscalln.panic")
// Create the switch on n.
sw := b.CreateSwitch(n, panicBB, maxArgs+1)
// We'll collect blocks and values for the PHI node.
var incomingVals []llvm.Value
var incomingBlocks []llvm.BasicBlock
// Generate a case for each arg count 0..maxArgs.
for i := 0; i <= maxArgs; i++ {
caseBB := b.insertBasicBlock("syscalln.case" + strconv.Itoa(i))
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), caseBB)
b.SetInsertPointAtEnd(caseBB)
// Load args[0] through args[i-1] from the slice data pointer.
var params []llvm.Value
var paramTypes []llvm.Type
for j := 0; j < i; j++ {
gep := b.CreateInBoundsGEP(b.uintptrType, argsPtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), uint64(j), false),
}, "")
arg := b.CreateLoad(b.uintptrType, gep, "")
params = append(params, arg)
paramTypes = append(paramTypes, b.uintptrType)
}
// SetLastError(0)
setCall := b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
var sp llvm.Value
if isI386 {
setCall.SetInstructionCallConv(llvm.X86StdcallCallConv)
sp = b.readStackPointer()
}
// Call fn(args...)
fnType := llvm.FunctionType(b.uintptrType, paramTypes, false)
syscallResult := b.CreateCall(fnType, fnPtr, params, "")
if isI386 {
syscallResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
b.writeStackPointer(sp)
}
// err = GetLastError()
errResult := b.CreateCall(getLastError.GlobalValueType(), getLastError, nil, "err")
if isI386 {
errResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
}
if b.uintptrType != b.ctx.Int32Type() {
errResult = b.CreateZExt(errResult, b.uintptrType, "err.uintptr")
}
// Build {r1, 0, err}
result := llvm.ConstNull(retType)
result = b.CreateInsertValue(result, syscallResult, 0, "")
result = b.CreateInsertValue(result, errResult, 2, "")
incomingVals = append(incomingVals, result)
incomingBlocks = append(incomingBlocks, b.Builder.GetInsertBlock())
b.CreateBr(mergeBB)
}
// Panic block for n > maxArgs.
b.SetInsertPointAtEnd(panicBB)
b.CreateUnreachable()
// Merge block: PHI node to select the result.
b.SetInsertPointAtEnd(mergeBB)
phi := b.CreatePHI(retType, "syscalln.result")
phi.AddIncoming(incomingVals, incomingBlocks)
return phi, nil
}
// createRawSyscallNoError emits instructions for the Linux-specific
// syscall.rawSyscallNoError function.
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
+34 -30
View File
@@ -1,6 +1,6 @@
; ModuleID = 'basic.go'
source_filename = "basic.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%main.kv = type { float, i32, i32, i32 }
@@ -10,30 +10,33 @@ target triple = "wasm32-unknown-wasi"
@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.b = hidden global [2 x ptr] zeroinitializer, align 4
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = add i32 %x, %y
ret i32 %0
}
; Function Attrs: nounwind
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq i32 %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -47,14 +50,14 @@ divbyzero.next: ; preds = %entry
ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2
call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable
}
declare void @runtime.divideByZeroPanic(ptr) #0
declare void @runtime.divideByZeroPanic(ptr) #1
; Function Attrs: nounwind
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -64,12 +67,12 @@ divbyzero.next: ; preds = %entry
ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2
call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -83,12 +86,12 @@ divbyzero.next: ; preds = %entry
ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2
call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -98,66 +101,66 @@ divbyzero.next: ; preds = %entry
ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2
call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp oeq float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp une float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp olt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp ole float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp ogt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp oge float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
entry:
ret float %x.r
}
; Function Attrs: nounwind
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
entry:
ret float %x.i
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry:
%0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i
@@ -167,7 +170,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry:
%0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i
@@ -177,7 +180,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry:
%0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i
@@ -191,18 +194,19 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.foo(ptr %context) unnamed_addr #1 {
define hidden void @main.foo(ptr %context) unnamed_addr #2 {
entry:
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
ret void
}
; Function Attrs: nounwind
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 {
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 {
entry:
ret void
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+29 -25
View File
@@ -1,91 +1,94 @@
; ModuleID = 'channel.go'
source_filename = "channel.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime.channelOp = type { ptr, ptr, i32, ptr }
%runtime.chanSelectState = type { ptr, ptr }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry:
%chan.op = alloca %runtime.channelOp, align 8
%chan.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
store i32 3, ptr %chan.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
ret void
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
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) #0
declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
; Function Attrs: nounwind
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry:
%chan.op = alloca %runtime.channelOp, align 8
%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 16, ptr nonnull %chan.op)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void
}
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #0
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
; Function Attrs: nounwind
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry:
%chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry:
%chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void
}
; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #1 {
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #2 {
entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4
store i32 1, ptr %select.send.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
store ptr %ch1, ptr %select.states.alloca, align 4
%select.states.alloca.repack1 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 4
%select.states.alloca.repack1 = getelementptr inbounds i8, ptr %select.states.alloca, i32 4
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
%0 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 8
%0 = getelementptr inbounds i8, ptr %select.states.alloca, i32 8
store ptr %ch2, ptr %0, align 4
%.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12
%.repack3 = getelementptr inbounds i8, ptr %select.states.alloca, i32 12
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) #3
%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
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
%1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0
@@ -102,9 +105,10 @@ select.body: ; preds = %select.next
br label %select.done
}
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #0
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #3 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
+27 -262
View File
@@ -6,16 +6,19 @@ target triple = "thumbv7m-unknown-unknown-eabi"
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface }
%runtime._interface = type { ptr, ptr }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
declare void @main.external(ptr) #1
declare void @main.external(ptr) #2
; Function Attrs: nounwind
define hidden void @main.deferSimple(ptr %context) unnamed_addr #0 {
define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
entry:
%defer.alloca = alloca { i32, ptr }, align 4
%deferPtr = alloca ptr, align 4
@@ -24,7 +27,7 @@ entry:
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
%defer.alloca.repack15 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
store ptr null, ptr %defer.alloca.repack15, 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
@@ -48,7 +51,7 @@ rundefers.loophead: ; preds = %3, %rundefers.block
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4
@@ -84,7 +87,7 @@ rundefers.loophead6: ; preds = %5, %lpad
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
rundefers.loop5: ; preds = %rundefers.loophead6
%stack.next.gep8 = getelementptr inbounds nuw i8, ptr %4, i32 4
%stack.next.gep8 = getelementptr inbounds i8, ptr %4, i32 4
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4
store ptr %stack.next9, ptr %deferPtr, align 4
%callback11 = load i32, ptr %4, align 4
@@ -109,14 +112,14 @@ rundefers.end3: ; preds = %rundefers.loophead6
}
; Function Attrs: nocallback nofree nosync nounwind willreturn
declare ptr @llvm.stacksave.p0() #2
declare ptr @llvm.stacksave.p0() #3
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #1
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #1
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
; Function Attrs: nounwind
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #0 {
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4
@@ -124,14 +127,14 @@ entry:
ret void
}
declare void @runtime.printlock(ptr) #1
declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #1
declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #0 {
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
entry:
%defer.alloca2 = alloca { i32, ptr }, align 4
%defer.alloca = alloca { i32, ptr }, align 4
@@ -141,11 +144,11 @@ entry:
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
%defer.alloca.repack22 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
store ptr null, ptr %defer.alloca.repack22, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4
store i32 1, ptr %defer.alloca2, align 4
%defer.alloca2.repack23 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
%defer.alloca2.repack23 = getelementptr inbounds i8, ptr %defer.alloca2, i32 4
store ptr %defer.alloca, ptr %defer.alloca2.repack23, 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
@@ -169,7 +172,7 @@ rundefers.loophead: ; preds = %4, %3, %rundefers.b
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4
@@ -215,7 +218,7 @@ rundefers.loophead10: ; preds = %7, %6, %lpad
br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9
rundefers.loop9: ; preds = %rundefers.loophead10
%stack.next.gep12 = getelementptr inbounds nuw i8, ptr %5, i32 4
%stack.next.gep12 = getelementptr inbounds i8, ptr %5, i32 4
%stack.next13 = load ptr, ptr %stack.next.gep12, align 4
store ptr %stack.next13, ptr %deferPtr, align 4
%callback15 = load i32, ptr %5, align 4
@@ -250,7 +253,7 @@ rundefers.end7: ; preds = %rundefers.loophead1
}
; Function Attrs: nounwind
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #0 {
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4
@@ -259,7 +262,7 @@ entry:
}
; Function Attrs: nounwind
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #0 {
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #4
@@ -267,247 +270,9 @@ entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #0 {
entry:
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.body
for.body: ; preds = %for.body, %entry
%defer.next = load ptr, ptr %deferPtr, align 4
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
store i32 0, ptr %defer.alloc.call, align 4
%defer.alloc.call.repack1 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
store ptr %defer.next, ptr %defer.alloc.call.repack1, align 4
%defer.alloc.call.repack3 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
store i32 8, ptr %defer.alloc.call.repack3, align 4
store ptr %defer.alloc.call, ptr %deferPtr, align 4
br label %for.body
recover: ; preds = %rundefers.end
ret void
lpad: ; No predecessors!
br label %rundefers.loophead
rundefers.loophead: ; preds = %rundefers.callback0, %lpad
br i1 poison, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
switch i32 poison, label %rundefers.default [
i32 0, label %rundefers.callback0
]
rundefers.callback0: ; preds = %rundefers.loop
br label %rundefers.loophead
rundefers.default: ; preds = %rundefers.loop
unreachable
rundefers.end: ; preds = %rundefers.loophead
br label %recover
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #3
; Function Attrs: nounwind
define hidden void @main.deferLoop(ptr %context) unnamed_addr #0 {
entry:
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.loop
for.loop: ; preds = %for.body, %entry
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
%2 = icmp slt i32 %1, 10
br i1 %2, label %for.body, label %for.done
for.body: ; preds = %for.loop
%defer.next = load ptr, ptr %deferPtr, align 4
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
store i32 0, ptr %defer.alloc.call, align 4
%defer.alloc.call.repack13 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
store ptr %defer.next, ptr %defer.alloc.call.repack13, align 4
%defer.alloc.call.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
store i32 %1, ptr %defer.alloc.call.repack15, align 4
store ptr %defer.alloc.call, ptr %deferPtr, align 4
%3 = add i32 %1, 1
br label %for.loop
for.done: ; preds = %for.loop
br label %rundefers.block
rundefers.after: ; preds = %rundefers.end
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
ret void
rundefers.block: ; preds = %for.done
br label %rundefers.loophead
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
%4 = load ptr, ptr %deferPtr, align 4
%stackIsNil = icmp eq ptr %4, null
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds nuw i8, ptr %4, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %4, align 4
switch i32 %callback, label %rundefers.default [
i32 0, label %rundefers.callback0
]
rundefers.callback0: ; preds = %rundefers.loop
%gep = getelementptr inbounds nuw i8, ptr %4, i32 8
%param = load i32, ptr %gep, align 4
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 %param, ptr undef) #4
call void @runtime.printunlock(ptr undef) #4
br label %rundefers.loophead
rundefers.default: ; preds = %rundefers.loop
unreachable
rundefers.end: ; preds = %rundefers.loophead
br label %rundefers.after
recover: ; preds = %rundefers.end1
ret void
lpad: ; No predecessors!
br label %rundefers.loophead4
rundefers.loophead4: ; preds = %rundefers.callback010, %lpad
br i1 poison, label %rundefers.end1, label %rundefers.loop3
rundefers.loop3: ; preds = %rundefers.loophead4
switch i32 poison, label %rundefers.default2 [
i32 0, label %rundefers.callback010
]
rundefers.callback010: ; preds = %rundefers.loop3
br label %rundefers.loophead4
rundefers.default2: ; preds = %rundefers.loop3
unreachable
rundefers.end1: ; preds = %rundefers.loophead4
br label %recover
}
; Function Attrs: nounwind
define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #0 {
entry:
%defer.alloca = alloca { i32, ptr, i32 }, align 4
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.loop
for.loop: ; preds = %for.body, %entry
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
%2 = icmp slt i32 %1, 10
br i1 %2, label %for.body, label %for.done
for.body: ; preds = %for.loop
%3 = add i32 %1, 1
br label %for.loop
for.done: ; preds = %for.loop
%defer.next = load ptr, ptr %deferPtr, align 4
store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack16 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
store ptr %defer.next, ptr %defer.alloca.repack16, align 4
%defer.alloca.repack18 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 8
store i32 1, ptr %defer.alloca.repack18, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4
br label %for.loop1
for.loop1: ; preds = %for.body2, %for.done
%4 = phi i32 [ 0, %for.done ], [ %6, %for.body2 ]
%5 = icmp slt i32 %4, 10
br i1 %5, label %for.body2, label %for.done3
for.body2: ; preds = %for.loop1
%6 = add i32 %4, 1
br label %for.loop1
for.done3: ; preds = %for.loop1
br label %rundefers.block
rundefers.after: ; preds = %rundefers.end
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
ret void
rundefers.block: ; preds = %for.done3
br label %rundefers.loophead
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
%7 = load ptr, ptr %deferPtr, align 4
%stackIsNil = icmp eq ptr %7, null
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds nuw i8, ptr %7, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %7, align 4
switch i32 %callback, label %rundefers.default [
i32 0, label %rundefers.callback0
]
rundefers.callback0: ; preds = %rundefers.loop
%gep = getelementptr inbounds nuw i8, ptr %7, i32 8
%param = load i32, ptr %gep, align 4
call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 %param, ptr undef) #4
call void @runtime.printunlock(ptr undef) #4
br label %rundefers.loophead
rundefers.default: ; preds = %rundefers.loop
unreachable
rundefers.end: ; preds = %rundefers.loophead
br label %rundefers.after
recover: ; preds = %rundefers.end4
ret void
lpad: ; No predecessors!
br label %rundefers.loophead7
rundefers.loophead7: ; preds = %rundefers.callback013, %lpad
br i1 poison, label %rundefers.end4, label %rundefers.loop6
rundefers.loop6: ; preds = %rundefers.loophead7
switch i32 poison, label %rundefers.default5 [
i32 0, label %rundefers.callback013
]
rundefers.callback013: ; preds = %rundefers.loop6
br label %rundefers.loophead7
rundefers.default5: ; preds = %rundefers.loop6
unreachable
rundefers.end4: ; preds = %rundefers.loophead7
br label %recover
}
attributes #0 = { 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 = { "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 = { nocallback nofree nosync nounwind willreturn }
attributes #3 = { 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,+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 #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 #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { nounwind }
attributes #5 = { nounwind returns_twice }
-20
View File
@@ -18,23 +18,3 @@ func deferMultiple() {
}()
external()
}
func deferInfiniteLoop() {
for {
defer print(8)
}
}
func deferLoop() {
for i := 0; i < 10; i++ {
defer print(i)
}
}
func deferBetweenLoops() {
for i := 0; i < 10; i++ {
}
defer print(1)
for i := 0; i < 10; i++ {
}
}
+17 -13
View File
@@ -1,18 +1,21 @@
; ModuleID = 'float.go'
source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 {
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -24,25 +27,25 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 {
define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
entry:
ret float 0x41F0000000000000
}
; Function Attrs: nounwind
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 {
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
entry:
ret i32 -1
}
; Function Attrs: nounwind
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 {
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 {
entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
}
; Function Attrs: nounwind
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 {
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #2 {
entry:
%0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
@@ -52,7 +55,7 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 {
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -65,7 +68,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 {
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02
@@ -77,7 +80,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 {
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 {
entry:
%abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02
@@ -90,5 +93,6 @@ entry:
ret i8 %0
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+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,-multivalue,-reference-types" }
attributes #1 = { "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,-multivalue,-reference-types" }
+16 -12
View File
@@ -1,46 +1,50 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 {
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp eq ptr %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.next: ; preds = %entry
call void %callback.funcptr(i32 3, ptr %callback.context) #2
call void %callback.funcptr(i32 3, ptr %callback.context) #3
ret void
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(ptr undef) #2
call void @runtime.nilPanic(ptr undef) #3
unreachable
}
declare void @runtime.nilPanic(ptr) #0
declare void @runtime.nilPanic(ptr) #1
; Function Attrs: nounwind
define hidden void @main.bar(ptr %context) unnamed_addr #1 {
define hidden void @main.bar(ptr %context) unnamed_addr #2 {
entry:
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 {
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 {
entry:
ret void
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
-8
View File
@@ -24,10 +24,6 @@ var (
x *byte
y [61]uintptr
}
struct5 *struct {
x *byte
y [30]uintptr
}
slice1 []byte
slice2 []*int
@@ -62,10 +58,6 @@ func newStruct() {
x *byte
y [61]uintptr
})
struct5 = new(struct {
x *byte
y [30]uintptr
})
}
func newFuncValue() *func() {
+26 -30
View File
@@ -1,6 +1,6 @@
; ModuleID = 'gc.go'
source_filename = "gc.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime._interface = type { ptr, ptr }
@@ -16,25 +16,27 @@ target triple = "wasm32-unknown-wasi"
@main.struct2 = hidden global ptr null, align 4
@main.struct3 = hidden global ptr null, align 4
@main.struct4 = hidden global ptr null, align 4
@main.struct5 = hidden global ptr null, align 4
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@"runtime/gc.layout:62-0100000000000020" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@"runtime/gc.layout:62-0100000000000000" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 {
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -52,11 +54,8 @@ entry:
ret void
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
; Function Attrs: nounwind
define hidden void @main.newArray(ptr %context) unnamed_addr #1 {
define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -72,7 +71,7 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 {
define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -81,20 +80,17 @@ entry:
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new1, ptr @main.struct2, align 4
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000020", ptr undef) #3
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new2, ptr @main.struct3, align 4
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000000", ptr undef) #3
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new3, ptr @main.struct4, align 4
%new4 = call align 4 dereferenceable(124) ptr @runtime.alloc(i32 124, ptr nonnull inttoptr (i32 127 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %new4, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new4, ptr @main.struct5, align 4
ret void
}
; Function Attrs: nounwind
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 {
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
@@ -103,35 +99,35 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 {
define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice, ptr @main.slice1, align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 8), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 8), align 4
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice1, ptr @main.slice2, align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 8), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 8), align 4
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice3, ptr @main.slice3, align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 8), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 8), align 4
ret void
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 {
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
store double %v.r, ptr %0, align 8
%.repack1 = getelementptr inbounds nuw i8, ptr %0, i32 8
%.repack1 = getelementptr inbounds i8, ptr %0, i32 8
store double %v.i, ptr %.repack1, align 8
%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
@@ -139,7 +135,7 @@ entry:
ret %runtime._interface %1
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+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,-multivalue,-reference-types" }
attributes #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+160 -78
View File
@@ -1,78 +1,144 @@
; ModuleID = 'generics.go'
source_filename = "generics.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%"main.Point[float32]" = type { float, float }
%"main.Point[int]" = type { i32, i32 }
%"main.Point[float32]" = type { float, float }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 {
define hidden void @main.main(i8* %context) unnamed_addr #1 {
entry:
%0 = call %"main.Point[float32]" @"main.Add[float32]"(float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, ptr undef)
%1 = call %"main.Point[int]" @"main.Add[int]"(i32 0, i32 0, i32 0, i32 0, ptr undef)
%bi = alloca %"main.Point[int]", align 8
%ai = alloca %"main.Point[int]", align 8
%bf = alloca %"main.Point[float32]", align 8
%af = alloca %"main.Point[float32]", align 8
%af.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
store float 0.000000e+00, float* %af.repack, align 8
%af.repack1 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
store float 0.000000e+00, float* %af.repack1, align 4
%0 = bitcast %"main.Point[float32]"* %af to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%bf.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
store float 0.000000e+00, float* %bf.repack, align 8
%bf.repack2 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
store float 0.000000e+00, float* %bf.repack2, align 4
%1 = bitcast %"main.Point[float32]"* %bf to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
%.unpack = load float, float* %.elt, align 8
%.elt3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
%.unpack4 = load float, float* %.elt3, align 4
%.elt5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
%.unpack6 = load float, float* %.elt5, align 8
%.elt7 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
%.unpack8 = load float, float* %.elt7, align 4
%2 = call %"main.Point[float32]" @"main.Add[float32]"(float %.unpack, float %.unpack4, float %.unpack6, float %.unpack8, i8* undef)
%ai.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
store i32 0, i32* %ai.repack, align 8
%ai.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
store i32 0, i32* %ai.repack9, align 4
%3 = bitcast %"main.Point[int]"* %ai to i8*
call void @runtime.trackPointer(i8* nonnull %3, i8* undef) #2
%bi.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
store i32 0, i32* %bi.repack, align 8
%bi.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
store i32 0, i32* %bi.repack10, align 4
%4 = bitcast %"main.Point[int]"* %bi to i8*
call void @runtime.trackPointer(i8* nonnull %4, i8* undef) #2
%.elt11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
%.unpack12 = load i32, i32* %.elt11, align 8
%.elt13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
%.unpack14 = load i32, i32* %.elt13, align 4
%.elt15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
%.unpack16 = load i32, i32* %.elt15, align 8
%.elt17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
%.unpack18 = load i32, i32* %.elt17, align 4
%5 = call %"main.Point[int]" @"main.Add[int]"(i32 %.unpack12, i32 %.unpack14, i32 %.unpack16, i32 %.unpack18, i8* undef)
ret void
}
; Function Attrs: nounwind
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, ptr %context) unnamed_addr #1 {
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, i8* %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
store float %a.X, ptr %a, align 4
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4
store float %a.Y, ptr %a.repack9, align 4
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
store float %b.X, ptr %b, align 4
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4
store float %b.Y, ptr %b.repack11, align 4
call void @main.checkSize(i32 4, ptr undef) #3
call void @main.checkSize(i32 8, ptr undef) #3
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
%complit = alloca %"main.Point[float32]", align 8
%b = alloca %"main.Point[float32]", align 8
%a = alloca %"main.Point[float32]", align 8
%a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
store float 0.000000e+00, float* %a.repack, align 8
%a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
store float 0.000000e+00, float* %a.repack9, align 4
%0 = bitcast %"main.Point[float32]"* %a to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
store float %a.X, float* %a.repack10, align 8
%a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
store float %a.Y, float* %a.repack11, align 4
%b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
store float 0.000000e+00, float* %b.repack, align 8
%b.repack13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
store float 0.000000e+00, float* %b.repack13, align 4
%1 = bitcast %"main.Point[float32]"* %b to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%b.repack14 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
store float %b.X, float* %b.repack14, align 8
%b.repack15 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
store float %b.Y, float* %b.repack15, align 4
call void @main.checkSize(i32 4, i8* undef) #2
call void @main.checkSize(i32 8, i8* undef) #2
%complit.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
store float 0.000000e+00, float* %complit.repack, align 8
%complit.repack17 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
store float 0.000000e+00, float* %complit.repack17, align 4
%2 = bitcast %"main.Point[float32]"* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
%3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry
br i1 false, label %deref.throw1, label %deref.next2
deref.next2: ; preds = %deref.next
%0 = load float, ptr %a, align 4
%1 = load float, ptr %b, align 4
%2 = fadd float %0, %1
%4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
%5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
%6 = load float, float* %5, align 8
%7 = load float, float* %4, align 8
%8 = fadd float %6, %7
br i1 false, label %deref.throw3, label %deref.next4
deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw5, label %deref.next6
deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
%5 = load float, ptr %4, align 4
%6 = load float, ptr %3, align 4
%9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
%10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
%11 = load float, float* %10, align 4
%12 = load float, float* %9, align 4
br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next6
store float %2, ptr %complit, align 4
store float %8, float* %3, align 8
br i1 false, label %store.throw7, label %store.next8
store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
%8 = fadd float %5, %6
store float %8, ptr %7, align 4
%.unpack = load float, ptr %complit, align 4
%9 = insertvalue %"main.Point[float32]" poison, float %.unpack, 0
%10 = insertvalue %"main.Point[float32]" %9, float %8, 1
ret %"main.Point[float32]" %10
%13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
%14 = fadd float %11, %12
store float %14, float* %13, align 4
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
%.unpack = load float, float* %.elt, align 8
%15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
%16 = insertvalue %"main.Point[float32]" %15, float %14, 1
ret %"main.Point[float32]" %16
deref.throw: ; preds = %entry
unreachable
@@ -93,64 +159,81 @@ store.throw7: ; preds = %store.next
unreachable
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
declare void @main.checkSize(i32, i8*) #0
declare void @main.checkSize(i32, ptr) #0
declare void @runtime.nilPanic(ptr) #0
declare void @runtime.nilPanic(i8*) #0
; Function Attrs: nounwind
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, ptr %context) unnamed_addr #1 {
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, i8* %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
store i32 %a.X, ptr %a, align 4
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4
store i32 %a.Y, ptr %a.repack9, align 4
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
store i32 %b.X, ptr %b, align 4
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4
store i32 %b.Y, ptr %b.repack11, align 4
call void @main.checkSize(i32 4, ptr undef) #3
call void @main.checkSize(i32 8, ptr undef) #3
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
%complit = alloca %"main.Point[int]", align 8
%b = alloca %"main.Point[int]", align 8
%a = alloca %"main.Point[int]", align 8
%a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
store i32 0, i32* %a.repack, align 8
%a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
store i32 0, i32* %a.repack9, align 4
%0 = bitcast %"main.Point[int]"* %a to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
store i32 %a.X, i32* %a.repack10, align 8
%a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
store i32 %a.Y, i32* %a.repack11, align 4
%b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
store i32 0, i32* %b.repack, align 8
%b.repack13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
store i32 0, i32* %b.repack13, align 4
%1 = bitcast %"main.Point[int]"* %b to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%b.repack14 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
store i32 %b.X, i32* %b.repack14, align 8
%b.repack15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
store i32 %b.Y, i32* %b.repack15, align 4
call void @main.checkSize(i32 4, i8* undef) #2
call void @main.checkSize(i32 8, i8* undef) #2
%complit.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
store i32 0, i32* %complit.repack, align 8
%complit.repack17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
store i32 0, i32* %complit.repack17, align 4
%2 = bitcast %"main.Point[int]"* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
%3 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry
br i1 false, label %deref.throw1, label %deref.next2
deref.next2: ; preds = %deref.next
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%2 = add i32 %0, %1
%4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
%5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
%6 = load i32, i32* %5, align 8
%7 = load i32, i32* %4, align 8
%8 = add i32 %6, %7
br i1 false, label %deref.throw3, label %deref.next4
deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw5, label %deref.next6
deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
%5 = load i32, ptr %4, align 4
%6 = load i32, ptr %3, align 4
%9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
%10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
%11 = load i32, i32* %10, align 4
%12 = load i32, i32* %9, align 4
br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next6
store i32 %2, ptr %complit, align 4
store i32 %8, i32* %3, align 8
br i1 false, label %store.throw7, label %store.next8
store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
%8 = add i32 %5, %6
store i32 %8, ptr %7, align 4
%.unpack = load i32, ptr %complit, align 4
%9 = insertvalue %"main.Point[int]" poison, i32 %.unpack, 0
%10 = insertvalue %"main.Point[int]" %9, i32 %8, 1
ret %"main.Point[int]" %10
%13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
%14 = add i32 %11, %12
store i32 %14, i32* %13, align 4
%.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
%.unpack = load i32, i32* %.elt, align 8
%15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
%16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
ret %"main.Point[int]" %16
deref.throw: ; preds = %entry
unreachable
@@ -171,7 +254,6 @@ store.throw7: ; preds = %store.next
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
+18 -14
View File
@@ -1,28 +1,31 @@
; ModuleID = 'go1.20.go'
source_filename = "go1.20.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime._string = type { ptr, i32 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %s.data
}
; Function Attrs: nounwind
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp slt i16 %len, 0
@@ -36,24 +39,25 @@ unsafe.String.next: ; preds = %entry
%5 = zext nneg i16 %len to i32
%6 = insertvalue %runtime._string undef, ptr %ptr, 0
%7 = insertvalue %runtime._string %6, i32 %5, 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret %runtime._string %7
unsafe.String.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #2
call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable
}
declare void @runtime.unsafeSlicePanic(ptr) #0
declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind
define hidden ptr @main.unsafeStringData(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %s.data
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+60 -62
View File
@@ -1,36 +1,36 @@
; ModuleID = 'go1.21.go'
source_filename = "go1.21.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime._string = type { ptr, i32 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #1 {
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
entry:
ret i32 %a
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smin.i32(i32, i32) #2
; Function Attrs: nounwind
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nounwind
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #1 {
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -38,7 +38,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #1 {
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -47,109 +47,91 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #1 {
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
ret i8 %0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.umin.i8(i8, i8) #2
; Function Attrs: nounwind
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #2
; Function Attrs: nounwind
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call float @llvm.minimum.f32(float %a, float %b)
ret float %0
%0 = fcmp olt float %a, %b
%1 = select i1 %0, float %a, float %b
ret float %1
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.minimum.f32(float, float) #2
; Function Attrs: nounwind
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #1 {
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call double @llvm.minimum.f64(double %a, double %b)
ret double %0
%0 = fcmp olt double %a, %b
%1 = select i1 %0, double %a, double %b
ret double %1
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare double @llvm.minimum.f64(double, double) #2
; Function Attrs: nounwind
define hidden %runtime._string @main.minString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #4
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
%6 = extractvalue %runtime._string %5, 0
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5
}
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
; Function Attrs: nounwind
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #2
; Function Attrs: nounwind
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #2
; Function Attrs: nounwind
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry:
%0 = call float @llvm.maximum.f32(float %a, float %b)
ret float %0
%0 = fcmp ogt float %a, %b
%1 = select i1 %0, float %a, float %b
ret float %1
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.maximum.f32(float, float) #2
; Function Attrs: nounwind
define hidden %runtime._string @main.maxString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #4
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
%6 = extractvalue %runtime._string %5, 0
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5
}
; Function Attrs: nounwind
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry:
%0 = shl i32 %s.len, 2
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
@@ -160,22 +142,38 @@ entry:
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
; Function Attrs: nounwind
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.clearMap(ptr dereferenceable_or_null(48) %m, ptr %context) unnamed_addr #1 {
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
entry:
call void @runtime.hashmapClear(ptr %m, ptr undef) #4
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
ret void
}
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(48), ptr) #0
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smin.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.umin.i8(i8, i8) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #4 = { nounwind }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #5 = { nounwind }
+68 -75
View File
@@ -5,50 +5,53 @@ target triple = "thumbv7m-unknown-unknown-eabi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #0 {
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
ret void
}
declare void @main.regularFunction(i32, ptr) #1
declare void @main.regularFunction(i32, ptr) #2
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
ret void
}
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #1
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #2
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #0 {
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
ret void
}
; Function Attrs: nounwind
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #0 {
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
@@ -56,28 +59,25 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #0 {
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
store i32 3, ptr %n, align 4
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 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) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
%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
%2 = load i32, ptr %n, align 4
call void @runtime.printlock(ptr undef) #11
call void @runtime.printint32(i32 %2, ptr undef) #11
call void @runtime.printunlock(ptr undef) #11
call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #9
ret void
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #0 {
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
entry:
store i32 7, ptr %context, align 4
ret void
@@ -87,29 +87,29 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
ret void
}
declare void @runtime.printlock(ptr) #1
declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #1
declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #0 {
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry:
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
%2 = getelementptr inbounds i8, ptr %0, i32 8
store ptr %fn.funcptr, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
%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
ret void
}
@@ -117,84 +117,77 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%4 = getelementptr inbounds i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #11
call void %5(i32 %1, ptr %3) #9
ret void
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #0 {
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #0 {
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
ret void
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #7
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #0 {
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11
call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void
}
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #2
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #0 {
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
%2 = getelementptr inbounds i8, ptr %0, i32 8
store i32 4, ptr %2, align 4
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
%3 = getelementptr inbounds i8, ptr %0, i32 12
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) #11
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) #11
%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
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%4 = getelementptr inbounds i8, ptr %0, i32 8
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%6 = getelementptr inbounds i8, ptr %0, i32 12
%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) #11
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
ret void
}
attributes #0 = { 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 = { "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 = { 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,+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 = { 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,+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 #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 #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 #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 #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 #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 #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #9 = { "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 #10 = { 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 #11 = { nounwind }
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 #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 #9 = { nounwind }
+78 -85
View File
@@ -1,89 +1,89 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
ret void
}
declare void @main.regularFunction(i32, ptr) #0
declare void @main.regularFunction(i32, ptr) #1
declare void @runtime.deadlock(ptr) #0
declare void @runtime.deadlock(ptr) #1
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
call void @runtime.deadlock(ptr undef) #11
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
call void @runtime.deadlock(ptr undef) #9
unreachable
}
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
ret void
}
; Function Attrs: nounwind
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
call void @runtime.deadlock(ptr undef) #11
call void @runtime.deadlock(ptr undef) #9
unreachable
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
store i32 3, ptr %n, align 4
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #11
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 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) #11
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
call void @runtime.printlock(ptr undef) #11
call void @runtime.printint32(i32 %2, ptr undef) #11
call void @runtime.printunlock(ptr undef) #11
call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #9
ret void
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
entry:
store i32 7, ptr %context, align 4
ret void
@@ -93,31 +93,31 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
call void @runtime.deadlock(ptr undef) #11
call void @runtime.deadlock(ptr undef) #9
unreachable
}
declare void @runtime.printlock(ptr) #0
declare void @runtime.printlock(ptr) #1
declare void @runtime.printint32(i32, ptr) #0
declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printunlock(ptr) #0
declare void @runtime.printunlock(ptr) #1
; 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 #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
%2 = getelementptr inbounds i8, ptr %0, i32 8
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) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void
}
@@ -125,87 +125,80 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%4 = getelementptr inbounds i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #11
call void @runtime.deadlock(ptr undef) #11
call void %5(i32 %1, ptr %3) #9
call void @runtime.deadlock(ptr undef) #9
unreachable
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
ret void
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #7
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
; 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(36) %ch, ptr %context) unnamed_addr #2 {
entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11
call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void
}
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #0
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
; 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 #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
%2 = getelementptr inbounds i8, ptr %0, i32 8
store i32 4, ptr %2, align 4
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
%3 = getelementptr inbounds i8, ptr %0, i32 12
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) #11
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
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%4 = getelementptr inbounds i8, ptr %0, i32 8
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%6 = getelementptr inbounds i8, ptr %0, i32 12
%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) #11
call void @runtime.deadlock(ptr undef) #11
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
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #4 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #9 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #10 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #11 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "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 #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "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 #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 #9 = { nounwind }
+45 -43
View File
@@ -1,6 +1,6 @@
; ModuleID = 'interface.go'
source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime._interface = type { ptr, ptr }
@@ -9,64 +9,65 @@ target triple = "wasm32-unknown-wasi"
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.signature:Error:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, { i32, [1 x ptr] }, [7 x i8] } { i8 116, i16 -32767, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, [7 x i8] c".error\00" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] } }, align 4
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.signature:String:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.typeid:basic:int" = external constant i8
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 {
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 {
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 {
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 {
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
}
; Function Attrs: nounwind
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry:
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #6
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -76,12 +77,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #0
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
; Function Attrs: nounwind
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry:
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -91,12 +92,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #2
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
; Function Attrs: nounwind
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -106,33 +107,34 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #3
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
; Function Attrs: nounwind
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry:
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #6
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
ret i8 %0
}
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #4
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
; Function Attrs: nounwind
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #6
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
%1 = extractvalue %runtime._string %0, 0
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._string %0
}
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #5
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+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,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
attributes #6 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "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 #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 #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 #7 = { nounwind }
+17 -13
View File
@@ -1,46 +1,50 @@
; ModuleID = 'pointer.go'
source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 {
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
entry:
ret [0 x i32] zeroinitializer
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 {
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 {
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 {
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
-5
View File
@@ -115,8 +115,3 @@ func doesNotEscapeParam(a *int, b []int, c chan int, d *[0]byte)
//go:noescape
func stillEscapes(a *int, b []int, c chan int, d *[0]byte) {
}
//go:noheap
func doesHeapAlloc() *int {
return new(int)
}
+31 -41
View File
@@ -1,6 +1,6 @@
; ModuleID = 'pragma.go'
source_filename = "pragma.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
@extern_global = external global [0 x i8], align 1
@@ -11,105 +11,95 @@ target triple = "wasm32-unknown-wasi"
@undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define void @extern_func() #2 {
define void @extern_func() #3 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 {
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
entry:
ret void
}
declare void @somepkg.someFunction2(ptr) #0
declare void @somepkg.someFunction2(ptr) #1
; Function Attrs: inlinehint nounwind
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #3 {
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #4 {
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #5 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.useGeneric(ptr %context) unnamed_addr #1 {
define hidden void @main.useGeneric(ptr %context) unnamed_addr #2 {
entry:
call void @"main.noinlineGenericFunc[int8]"(ptr undef)
ret void
}
; Function Attrs: noinline nounwind
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #4 {
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #5 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.functionInSection(ptr %context) unnamed_addr #4 section ".special_function_section" {
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
entry:
ret void
}
; Function Attrs: noinline nounwind
define void @exportedFunctionInSection() #5 section ".special_function_section" {
define void @exportedFunctionInSection() #6 section ".special_function_section" {
entry:
ret void
}
declare void @main.declaredImport() #6
declare void @main.declaredImport() #7
declare void @imported() #7
declare void @imported() #8
; Function Attrs: nounwind
define void @exported() #8 {
define void @exported() #9 {
entry:
ret void
}
declare void @main.undefinedFunctionNotInSection(ptr) #0
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) #0
declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #1
; Function Attrs: nounwind
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 #1 {
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 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden ptr @main.doesHeapAlloc(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%new = call align 4 dereferenceable(4) ptr @runtime.alloc_noheap(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #10
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #10
ret ptr %new
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc_noheap(i32, ptr, ptr) #9
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
attributes #9 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #10 = { nounwind }
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 #1 = { "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,-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" }
+69 -77
View File
@@ -1,30 +1,33 @@
; ModuleID = 'slice.go'
source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry:
ret i32 %ints.len
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry:
ret i32 %ints.cap
}
; Function Attrs: nounwind
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 {
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 {
entry:
%.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw
@@ -35,93 +38,84 @@ lookup.next: ; preds = %entry
ret i32 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #5
call void @runtime.lookupPanic(ptr undef) #3
unreachable
}
declare void @runtime.lookupPanic(ptr) #0
declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #5
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
store i32 1, ptr %varargs, align 4
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4
%0 = getelementptr inbounds i8, ptr %varargs, i32 4
store i32 2, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8
%1 = getelementptr inbounds i8, ptr %varargs, i32 8
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 nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%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.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1
%4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %4
}
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #0
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
%copy.size = shl nuw i32 %copy.n, 2
call void @llvm.memmove.p0.p0.i32(ptr align 4 %dst.data, ptr align 4 %src.data, i32 %copy.size, i1 false)
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
ret i32 %copy.n
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #3
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #4
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.next: ; preds = %entry
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5
call void @runtime.slicePanic(ptr undef) #3
unreachable
}
declare void @runtime.slicePanic(ptr) #0
declare void @runtime.slicePanic(ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0
@@ -129,20 +123,20 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = shl nuw i32 %len, 1
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5
call void @runtime.slicePanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1431655765
@@ -150,20 +144,20 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5
call void @runtime.slicePanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1073741823
@@ -171,39 +165,39 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = shl nuw i32 %len, 2
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5
call void @runtime.slicePanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 {
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = getelementptr i8, ptr %p, i32 %len
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %0
}
; Function Attrs: nounwind
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 {
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = trunc i64 %len to i32
%1 = getelementptr i8, ptr %p, i32 %0
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %1
}
; Function Attrs: nounwind
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
@@ -212,18 +206,18 @@ slicetoarray.next: ; preds = %entry
ret ptr %s.data
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(ptr undef) #5
call void @runtime.sliceToArrayPointerPanic(ptr undef) #3
unreachable
}
declare void @runtime.sliceToArrayPointerPanic(ptr) #0
declare void @runtime.sliceToArrayPointerPanic(ptr) #1
; Function Attrs: nounwind
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 {
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #5
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
@@ -234,7 +228,7 @@ slicetoarray.throw: ; preds = %entry
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i32 %len, 1073741823
@@ -248,18 +242,18 @@ unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5
call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable
}
declare void @runtime.unsafeSlicePanic(ptr) #0
declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp eq ptr %ptr, null
@@ -272,16 +266,16 @@ unsafe.Slice.next: ; preds = %entry
%4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5
call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823
@@ -296,16 +290,16 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5
call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823
@@ -320,17 +314,15 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5
call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+28 -24
View File
@@ -1,40 +1,43 @@
; ModuleID = 'string.go'
source_filename = "string.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%runtime._string = type { ptr, i32 }
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
entry:
ret %runtime._string { ptr @"main$string", i32 3 }
}
; Function Attrs: nounwind
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 {
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
entry:
ret %runtime._string zeroinitializer
}
; Function Attrs: nounwind
define hidden i32 @main.stringLen(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry:
ret i32 %s.len
}
; Function Attrs: nounwind
define hidden i8 @main.stringIndex(ptr readonly %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 {
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
entry:
%.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
@@ -45,55 +48,56 @@ lookup.next: ; preds = %entry
ret i8 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2
call void @runtime.lookupPanic(ptr undef) #3
unreachable
}
declare void @runtime.lookupPanic(ptr) #0
declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind
define hidden i1 @main.stringCompareEqual(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry:
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
ret i1 %0
}
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #0
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1
; Function Attrs: nounwind
define hidden i1 @main.stringCompareUnequal(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry:
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
%1 = xor i1 %0, true
ret i1 %1
}
; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry:
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #2
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
ret i1 %0
}
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
; Function Attrs: nounwind
define hidden i8 @main.stringLookup(ptr readonly %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 {
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
entry:
%0 = zext i8 %x to i32
%.not = icmp ugt i32 %s.len, %0
%.not = icmp ult i32 %0, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.next: ; preds = %entry
%1 = getelementptr inbounds nuw i8, ptr %s.data, i32 %0
%1 = getelementptr inbounds i8, ptr %s.data, i32 %0
%2 = load i8, ptr %1, align 1
ret i8 %2
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2
call void @runtime.lookupPanic(ptr undef) #3
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+57 -27
View File
@@ -1,20 +1,23 @@
; ModuleID = 'zeromap.go'
source_filename = "zeromap.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-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"
%main.hasPadding = type { i1, i32, i1 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 {
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
entry:
%hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4
@@ -24,23 +27,29 @@ entry:
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4
%3 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
%5 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
%4 = load i32, ptr %hashmap.value, align 4
%6 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %4
ret i32 %6
}
; 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) #4
declare i1 @runtime.hashmapGenericGet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, i32, ptr) #0
declare void @runtime.memzero(ptr, i32, ptr) #1
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1
; 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) #4
; Function Attrs: noinline nounwind
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
entry:
%hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4
@@ -51,16 +60,20 @@ entry:
store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void
}
declare void @runtime.hashmapGenericSet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, ptr) #0
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1
; Function Attrs: noinline nounwind
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4
@@ -68,18 +81,26 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
%1 = load i32, ptr %hashmap.value, align 4
%5 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %1
ret i32 %5
}
; Function Attrs: noinline nounwind
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4
@@ -88,23 +109,32 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void
}
; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 {
define hidden void @main.main(ptr %context) unnamed_addr #2 {
entry:
ret void
}
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
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 #1 = { "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,-multivalue,-reference-types" }
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind }
-1
View File
@@ -38,7 +38,6 @@ func TestErrors(t *testing.T) {
{name: "loader-invaliddep"},
{name: "loader-invalidpackage"},
{name: "loader-nopackage"},
{name: "noheap", target: "cortex-m-qemu"},
{name: "optimizer"},
{name: "syntax"},
{name: "types"},
Generated
+4 -4
View File
@@ -20,16 +20,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1770136044,
"narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=",
"lastModified": 1747953325,
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e",
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-25.11",
"ref": "nixos-25.05",
"type": "indirect"
}
},
+1 -1
View File
@@ -34,7 +34,7 @@
inputs = {
# Use a recent stable release, but fix the version to make it reproducible.
# This version should be updated from time to time.
nixpkgs.url = "nixpkgs/nixos-25.11";
nixpkgs.url = "nixpkgs/nixos-25.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
+13 -29
View File
@@ -1,53 +1,37 @@
module github.com/tinygo-org/tinygo
go 1.23.0
go 1.22.0
require (
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6
github.com/gofrs/flock v0.8.1
github.com/golangci/misspell v0.6.0
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-tty v0.0.4
github.com/mgechev/revive v1.3.9
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
github.com/tetratelabs/wazero v1.9.0
go.bug.st/serial v1.6.4
go.bytecodealliance.org v0.6.2
go.bytecodealliance.org/cm v0.2.2
github.com/tetratelabs/wazero v1.6.0
go.bug.st/serial v1.6.0
golang.org/x/net v0.35.0
golang.org/x/sys v0.30.0
golang.org/x/tools v0.30.0
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/espflasher v0.6.0
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74
)
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/regclient/regclient v0.8.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
golang.org/x/mod v0.23.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/text v0.22.0 // indirect
)
+28 -69
View File
@@ -1,36 +1,34 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -42,57 +40,20 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
@@ -102,7 +63,8 @@ golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
@@ -115,10 +77,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
tinygo.org/x/espflasher v0.6.0 h1:CHbGMHAIWq1tB8FKd/QwBpNFw1jvHHxpmvZiF+QOYUo=
tinygo.org/x/espflasher v0.6.0/go.mod h1:tr5u08HoE67WD5zxJesCiiVF/R1b6Akz3yXwh5zah8U=
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6 h1:QSnqFgNV2Ij0T4hM2qKv53fcDAFElxClPjVUZXzYkWU=
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74 h1:ovavgTdIBWCH8YWlcfq9gkpoyT1+IxMKSn+Df27QwE8=
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const version = "0.42.0-dev"
const version = "0.39.0-dev"
// Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012).
+30
View File
@@ -0,0 +1,30 @@
// TODO: remove this (by merging it into the top-level go.mod)
// once the top level go.mod specifies a go new enough to make our version of misspell happy.
module tools
go 1.21
require (
github.com/golangci/misspell v0.6.0
github.com/mgechev/revive v1.3.9
)
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.11.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.23.0 // indirect
)
+56
View File
@@ -0,0 +1,56 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1 -4
View File
@@ -2,15 +2,12 @@
// Install tools specified in go.mod.
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
package main
package tools
import (
_ "github.com/golangci/misspell"
_ "github.com/mgechev/revive"
_ "go.bytecodealliance.org/cm"
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
)
//go:generate go install github.com/golangci/misspell/cmd/misspell
//go:generate go install github.com/mgechev/revive
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
+5
View File
@@ -0,0 +1,5 @@
# wasm-tools directory
This directory has a separate `go.mod` file because the `wasm-tools-go` module requires Go 1.22, while TinyGo itself supports Go 1.19.
When the minimum Go version for TinyGo is 1.22, this directory can be folded into `internal/tools` and the `go.mod` and `go.sum` files deleted.
+22
View File
@@ -0,0 +1,22 @@
module github.com/tinygo-org/tinygo/internal/wasm-tools
go 1.23.0
require (
go.bytecodealliance.org v0.6.2
go.bytecodealliance.org/cm v0.2.2
)
require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/regclient/regclient v0.8.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sys v0.31.0 // indirect
)
+48
View File
@@ -0,0 +1,48 @@
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
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/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.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+12
View File
@@ -0,0 +1,12 @@
//go:build tools
// Install tools specified in go.mod.
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
package tools
import (
_ "go.bytecodealliance.org/cm"
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
)
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
+1 -2
View File
@@ -19,7 +19,6 @@ var (
errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
errMapAlreadyCreated = errors.New("interp: map already created")
errLoopUnrolled = errors.New("interp: loop unrolled")
errLoopTooLong = errors.New("interp: loop ran too many iterations")
)
// This is one of the errors that can be returned from toLLVMValue when the
@@ -30,7 +29,7 @@ var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not
func isRecoverableError(err error) bool {
return err == errIntegerAsPointer || err == errUnsupportedInst ||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
err == errLoopUnrolled || err == errLoopTooLong || err == errInvalidPtrToIntSize
err == errLoopUnrolled
}
// ErrorLine is one line in a traceback. The position may be missing.
+30 -33
View File
@@ -19,38 +19,35 @@ const checks = true
// runner contains all state related to one interp run.
type runner struct {
mod llvm.Module
targetData llvm.TargetData
builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData
dataPtrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
byteOrder binary.ByteOrder // big-endian or little-endian
debug bool // log debug messages
pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions
objects []object // slice of objects in memory
globals map[llvm.Value]int // map from global to index in objects slice
start time.Time
timeout time.Duration
maxLoopIterations int
callsExecuted uint64
interpErr error // set by Uint/Int when they encounter pointer data
mod llvm.Module
targetData llvm.TargetData
builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData
dataPtrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
byteOrder binary.ByteOrder // big-endian or little-endian
debug bool // log debug messages
pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions
objects []object // slice of objects in memory
globals map[llvm.Value]int // map from global to index in objects slice
start time.Time
timeout time.Duration
callsExecuted uint64
}
func newRunner(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bool) *runner {
func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
r := runner{
mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()),
byteOrder: llvmutil.ByteOrder(mod.Target()),
debug: debug,
functionCache: make(map[llvm.Value]*function),
objects: []object{{}},
globals: make(map[llvm.Value]int),
start: time.Now(),
timeout: timeout,
maxLoopIterations: maxLoopIterations,
mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()),
byteOrder: llvmutil.ByteOrder(mod.Target()),
debug: debug,
functionCache: make(map[llvm.Value]*function),
objects: []object{{}},
globals: make(map[llvm.Value]int),
start: time.Now(),
timeout: timeout,
}
r.pointerSize = uint32(r.targetData.PointerSize())
r.dataPtrType = llvm.PointerType(mod.Context().Int8Type(), 0)
@@ -67,8 +64,8 @@ func (r *runner) dispose() {
// Run evaluates runtime.initAll function as much as possible at compile time.
// Set debug to true if it should print output while running.
func Run(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bool) error {
r := newRunner(mod, timeout, maxLoopIterations, debug)
func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
r := newRunner(mod, timeout, debug)
defer r.dispose()
initAll := mod.NamedFunction("runtime.initAll")
@@ -207,10 +204,10 @@ func Run(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bo
// RunFunc evaluates a single package initializer at compile time.
// Set debug to true if it should print output while running.
func RunFunc(fn llvm.Value, timeout time.Duration, maxLoopIterations int, debug bool) error {
func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
// Create and initialize *runner object.
mod := fn.GlobalParent()
r := newRunner(mod, timeout, maxLoopIterations, debug)
r := newRunner(mod, timeout, debug)
defer r.dispose()
initName := fn.Name()
if !strings.HasSuffix(initName, ".init") {
+12 -3
View File
@@ -2,6 +2,7 @@ package interp
import (
"os"
"strconv"
"strings"
"testing"
"time"
@@ -10,17 +11,25 @@ import (
)
func TestInterp(t *testing.T) {
llvmVersion, err := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
if err != nil {
// Note: this should never happen and if it does, it will always happen
// for a particular build because llvm.Version is a constant.
panic(err)
}
for _, name := range []string{
"basic",
"phi",
"slice-copy",
"consteval",
"intrinsics",
"copy",
"interface",
"revert",
"alloc",
} {
name := name // make local to this closure
if name == "slice-copy" && llvmVersion < 14 {
continue
}
t.Run(name, func(t *testing.T) {
t.Parallel()
runTest(t, "testdata/"+name)
@@ -44,7 +53,7 @@ func runTest(t *testing.T, pathPrefix string) {
defer mod.Dispose()
// Perform the transform.
err = Run(mod, 10*time.Minute, DefaultMaxInterpBlockEntries, false)
err = Run(mod, 10*time.Minute, false)
if err != nil {
if err, match := err.(*Error); match {
println(err.Error())
+111 -54
View File
@@ -12,12 +12,6 @@ import (
"tinygo.org/x/go-llvm"
)
// DefaultMaxInterpBlockEntries is the default maximum number of times a single
// basic block may be entered during interpretation of one function call. This
// limits how far the interpreter will unroll or evaluate loops before deferring
// the init function to runtime.
const DefaultMaxInterpBlockEntries = 1000
func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent string) (value, memoryView, *Error) {
mem := memoryView{r: r, parent: parentMem}
locals := make([]value, len(fn.locals))
@@ -32,10 +26,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// This is used to prevent unrolling.
var runtimeBlocks map[int]struct{}
// Track how many times each basic block has been entered, to detect
// loops that are too expensive to evaluate at compile time.
var blockCounts map[int]int
// Start with the first basic block and the first instruction.
// Branch instructions may modify both bb and instIndex when branching.
bb := fn.blocks[0]
@@ -46,18 +36,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
for instIndex := 0; instIndex < len(bb.instructions); instIndex++ {
if instIndex == 0 {
// This is the start of a new basic block.
// Check whether this block has been entered too many times,
// which indicates an expensive loop that should be deferred
// to runtime.
if blockCounts == nil {
blockCounts = make(map[int]int)
}
blockCounts[currentBB]++
if r.maxLoopIterations > 0 && blockCounts[currentBB] > r.maxLoopIterations {
return nil, mem, r.errorAt(bb.instructions[0], errLoopTooLong)
}
if len(mem.instructions) != startRTInsts {
if _, ok := runtimeBlocks[lastBB]; ok {
// This loop has been unrolled.
@@ -299,7 +277,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// means that monotonic time in the time package is counted from
// time.Time{}.Sub(1), which should be fine.
locals[inst.localIndex] = literalValue{uint64(0)}
case callFn.name == "runtime.alloc" || callFn.name == "runtime.alloc_noheap":
case callFn.name == "runtime.alloc":
// Allocate heap memory. At compile time, this is instead done
// by creating a global variable.
@@ -334,28 +312,33 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
fmt.Fprintln(os.Stderr, indent+"runtime.alloc:", size, "->", ptr)
}
locals[inst.localIndex] = ptr
case strings.HasPrefix(callFn.name, "llvm.umin."):
locals[inst.localIndex] = makeLiteralInt(min(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.smin."):
locals[inst.localIndex] = makeLiteralInt(uint64(min(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.umax."):
locals[inst.localIndex] = makeLiteralInt(max(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.smax."):
locals[inst.localIndex] = makeLiteralInt(uint64(max(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
// Copy a block of memory from one pointer to another.
if operands[4].Uint(r) != 0 {
// This is a volatile copy/move.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
}
continue
case callFn.name == "runtime.sliceCopy":
// sliceCopy implements the built-in copy function for slices.
// It is implemented here so that it can be used even if the
// runtime implementation is not available. Doing it this way
// may also be faster.
// Code:
// func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int {
// n := srcLen
// if n > dstLen {
// n = dstLen
// }
// memmove(dst, src, n*elemSize)
// return int(n)
// }
dstLen := operands[3].Uint(r)
srcLen := operands[4].Uint(r)
elemSize := operands[5].Uint(r)
n := srcLen
if n > dstLen {
n = dstLen
}
nBytes := operands[3].Uint(r)
if nBytes != 0 {
if r.debug {
fmt.Fprintln(os.Stderr, indent+"copy:", operands[1], operands[2], n)
}
if n != 0 {
// Only try to copy bytes when there are any bytes to copy.
// This is not just an optimization. If one of the pointers
// This is not just an optimization. If one of the slices
// (or both) are nil, the asPointer method call will fail
// even though copying a nil slice is allowed.
dst, err := operands[1].asPointer(r)
@@ -380,10 +363,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
continue
}
nBytes := uint32(n * elemSize)
srcObj := mem.get(src.index())
dstObj := mem.getWritable(dst.index())
if srcObj.buffer == nil || dstObj.buffer == nil {
// If the buffer is nil, it means the memory is external.
// If the buffer is nil, it means the slice is external.
// This can happen for example when copying data out of
// a //go:embed slice, which is not available at interp
// time.
@@ -396,10 +380,33 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
dstBuf := dstObj.buffer.asRawValue(r)
srcBuf := srcObj.buffer.asRawValue(r)
copy(dstBuf.buf[dst.offset():][:nBytes], srcBuf.buf[src.offset():][:nBytes])
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
}
locals[inst.localIndex] = makeLiteralInt(n, inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
// Copy a block of memory from one pointer to another.
dst, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
src, err := operands[2].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
nBytes := uint32(operands[3].Uint(r))
dstObj := mem.getWritable(dst.index())
dstBuf := dstObj.buffer.asRawValue(r)
if mem.get(src.index()).buffer == nil {
// Looks like the source buffer is not defined.
// This can happen with //extern or //go:embed.
return nil, mem, r.errorAt(inst, errUnsupportedRuntimeInst)
}
srcBuf := mem.get(src.index()).buffer.asRawValue(r)
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
case callFn.name == "runtime.typeAssert":
// This function must be implemented manually as it is normally
// implemented by the interface lowering pass.
@@ -435,6 +442,64 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Special function that will trigger an error.
// This is used to test error reporting.
return nil, mem, r.errorAt(inst, errors.New("test error"))
case strings.HasSuffix(callFn.name, ".$typeassert"):
if r.debug {
fmt.Fprintln(os.Stderr, indent+"interface assert:", operands[1:])
}
// Load various values for the interface implements check below.
typecodePtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
// typecodePtr always point to the numMethod field in the type
// description struct. The methodSet, when present, comes right
// before the numMethod field (the compiler doesn't generate
// method sets for concrete types without methods).
// Considering that the compiler doesn't emit interface type
// asserts for interfaces with no methods (as the always succeed)
// then if the offset is zero, this assert must always fail.
if typecodePtr.offset() == 0 {
locals[inst.localIndex] = literalValue{uint8(0)}
break
}
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
methodSet := mem.get(methodSetPtr.index()).llvmGlobal.Initializer()
numMethods := int(r.builder.CreateExtractValue(methodSet, 0, "").ZExtValue())
llvmFn := inst.llvmInst.CalledValue()
methodSetAttr := llvmFn.GetStringAttributeAtIndex(-1, "tinygo-methods")
methodSetString := methodSetAttr.GetStringValue()
// Make a set of all the methods on the concrete type, for
// easier checking in the next step.
concreteTypeMethods := map[string]struct{}{}
for i := 0; i < numMethods; i++ {
methodInfo := r.builder.CreateExtractValue(methodSet, 1, "")
name := r.builder.CreateExtractValue(methodInfo, i, "").Name()
concreteTypeMethods[name] = struct{}{}
}
// Check whether all interface methods are also in the list
// of defined methods calculated above. This is the interface
// assert itself.
assertOk := uint8(1) // i1 true
for _, name := range strings.Split(methodSetString, "; ") {
if _, ok := concreteTypeMethods[name]; !ok {
// There is a method on the interface that is not
// implemented by the type. The assertion will fail.
assertOk = 0 // i1 false
break
}
}
// If assertOk is still 1, the assertion succeeded.
locals[inst.localIndex] = literalValue{assertOk}
case strings.HasSuffix(callFn.name, "$invoke"):
// This thunk is the interface method dispatcher: it is called
// with all regular parameters and a type code. It will then
@@ -512,7 +577,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// runtime instead of at compile time. But we need to
// revert any changes made by the call first.
if r.debug {
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Error())
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Err)
}
callMem.revert()
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
@@ -847,14 +912,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
return nil, mem, r.errorAt(inst, errUnsupportedInst)
}
// Check if an instruction triggered a recoverable error (e.g.,
// trying to interpret pointer data as integer bytes).
if r.interpErr != nil {
err := r.interpErr
r.interpErr = nil
return nil, mem, r.errorAt(inst, err)
}
}
return nil, mem, r.errorAt(bb.instructions[len(bb.instructions)-1], errors.New("interp: reached end of basic block without terminator"))
}
+5 -11
View File
@@ -556,13 +556,11 @@ func (v pointerValue) asRawValue(r *runner) rawValue {
}
func (v pointerValue) Uint(r *runner) uint64 {
r.interpErr = errUnsupportedInst
return 0
panic("cannot convert pointer to integer")
}
func (v pointerValue) Int(r *runner) int64 {
r.interpErr = errUnsupportedInst
return 0
panic("cannot convert pointer to integer")
}
func (v pointerValue) equal(rhs pointerValue) bool {
@@ -738,12 +736,11 @@ func (v rawValue) asRawValue(r *runner) rawValue {
return v
}
func (v rawValue) bytes(r *runner) []byte {
func (v rawValue) bytes() []byte {
buf := make([]byte, len(v.buf))
for i, p := range v.buf {
if p > 255 {
r.interpErr = errUnsupportedInst
return buf
panic("cannot convert pointer value to byte")
}
buf[i] = byte(p)
}
@@ -751,10 +748,7 @@ func (v rawValue) bytes(r *runner) []byte {
}
func (v rawValue) Uint(r *runner) uint64 {
buf := v.bytes(r)
if r.interpErr != nil {
return 0
}
buf := v.bytes()
switch len(v.buf) {
case 1:
+1 -1
View File
@@ -10,7 +10,7 @@ target triple = "x86_64--linux"
@main.exposedValue2 = local_unnamed_addr global i16 0
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
@main.negativeGEP = global ptr getelementptr inbounds nuw (i8, ptr @main.negativeGEP, i64 2)
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
declare void @runtime.printint64(i64) unnamed_addr
+1 -1
View File
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
@ptrToIntResult = local_unnamed_addr global i8 2
@pointerTagResult = local_unnamed_addr global i64 2
@someArray = internal global { i16, i8, i8 } zeroinitializer
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds nuw (i8, ptr @someArray, i64 2)
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds (i8, ptr @someArray, i64 2)
define void @runtime.initAll() local_unnamed_addr {
ret void
-68
View File
@@ -1,68 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@string = internal unnamed_addr constant [3 x i8] c"foo"
@moveDst = global [3 x i8] zeroinitializer
@copyDst = global [3 x i8] zeroinitializer
@externalSrc = external global [2 x i8]
@moveExternalDst = global [2 x i8] zeroinitializer
@moveEscapedSrc = global [4 x i8] c"abcd"
@moveEscapedDst = global [4 x i8] zeroinitializer
@volatileSrc = global [2 x i8] c"xy"
@volatileDst = global [2 x i8] zeroinitializer
declare void @use(ptr)
define void @runtime.initAll() {
call void @main.init()
ret void
}
define internal void @main.init() {
call void @testMove()
call void @testCopy()
call void @testMoveExternal()
call void @testMoveEscaped()
call void @testVolatileCopy()
ret void
}
; Test a simple memmove between globals.
define internal void @testMove() {
call void @llvm.memmove.p0.p0.i64(ptr @moveDst, ptr @string, i64 3, i1 false)
ret void
}
; Test a simple memcpy between globals.
define internal void @testCopy() {
call void @llvm.memcpy.p0.p0.i64(ptr @copyDst, ptr @string, i64 3, i1 false)
ret void
}
; Test a memmove from an external global.
; This should be run at runtime.
define internal void @testMoveExternal() {
call void @llvm.memmove.p0.p0.i64(ptr @moveExternalDst, ptr @externalSrc, i64 2, i1 false)
ret void
}
; Test a memmove from an escaped (and potentially modified) source buffer.
define internal void @testMoveEscaped() {
call void @use(ptr @moveEscapedSrc)
call void @llvm.memmove.p0.p0.i64(ptr @moveEscapedDst, ptr @moveEscapedSrc, i64 4, i1 false)
ret void
}
; Test a volatile memcpy.
; This should always be run at runtime.
define internal void @testVolatileCopy() {
call void @llvm.memcpy.p0.p0.i64(ptr @volatileDst, ptr @volatileSrc, i64 2, i1 true)
ret void
}
declare void @llvm.memmove.p0.p0.i64(ptr, ptr, i64, i1)
declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
-27
View File
@@ -1,27 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@moveDst = local_unnamed_addr global [3 x i8] c"foo"
@copyDst = local_unnamed_addr global [3 x i8] c"foo"
@externalSrc = external local_unnamed_addr global [2 x i8]
@moveExternalDst = local_unnamed_addr global [2 x i8] zeroinitializer
@moveEscapedSrc = global [4 x i8] c"abcd"
@moveEscapedDst = local_unnamed_addr global [4 x i8] zeroinitializer
@volatileSrc = global [2 x i8] c"xy"
@volatileDst = global [2 x i8] zeroinitializer
declare void @use(ptr) local_unnamed_addr
define void @runtime.initAll() local_unnamed_addr {
call void @llvm.memmove.p0.p0.i64(ptr @moveExternalDst, ptr @externalSrc, i64 2, i1 false)
call void @use(ptr @moveEscapedSrc)
call void @llvm.memmove.p0.p0.i64(ptr @moveEscapedDst, ptr @moveEscapedSrc, i64 4, i1 false)
call void @llvm.memcpy.p0.p0.i64(ptr @volatileDst, ptr @volatileSrc, i64 2, i1 true)
ret void
}
declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg) #0
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
-52
View File
@@ -1,52 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@uminResult = global i32 0
@sminResult = global i32 0
@umaxResult = global i32 0
@smaxResult = global i32 0
define void @runtime.initAll() {
call void @main.init()
ret void
}
define internal void @main.init() {
call void @testUMin()
call void @testSMin()
call void @testUMax()
call void @testSMax()
ret void
}
define internal void @testUMin() {
%umin = call i32 @llvm.umin.i32(i32 12, i32 -1)
store i32 %umin, ptr @uminResult
ret void
}
declare i32 @llvm.umin.i32(i32, i32)
define internal void @testSMin() {
%smin = call i32 @llvm.smin.i32(i32 12, i32 -1)
store i32 %smin, ptr @sminResult
ret void
}
declare i32 @llvm.smin.i32(i32, i32)
define internal void @testUMax() {
%umax = call i32 @llvm.umax.i32(i32 12, i32 -1)
store i32 %umax, ptr @umaxResult
ret void
}
declare i32 @llvm.umax.i32(i32, i32)
define internal void @testSMax() {
%smax = call i32 @llvm.smax.i32(i32 12, i32 -1)
store i32 %smax, ptr @smaxResult
ret void
}
declare i32 @llvm.smax.i32(i32, i32)
-11
View File
@@ -1,11 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@uminResult = local_unnamed_addr global i32 12
@sminResult = local_unnamed_addr global i32 -1
@umaxResult = local_unnamed_addr global i32 -1
@smaxResult = local_unnamed_addr global i32 12
define void @runtime.initAll() local_unnamed_addr {
ret void
}
+124
View File
@@ -0,0 +1,124 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.uint8SliceSrc.buf = internal global [2 x i8] c"\03d"
@main.uint8SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.uint8SliceSrc.buf, i64 2, i64 2 }
@main.uint8SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
@main.int16SliceSrc.buf = internal global [3 x i16] [i16 5, i16 123, i16 1024]
@main.int16SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.int16SliceSrc.buf, i64 3, i64 3 }
@main.int16SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
@main.sliceSrcUntaint.buf = internal global [2 x i8] c"ab"
@main.sliceDstUntaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal1.buf = external global [2 x i8]
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
@main.sliceDstExternal2.buf = external global [2 x i8]
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
declare ptr @runtime.alloc(i64, ptr) unnamed_addr
declare void @runtime.printuint8(i8)
declare void @runtime.printint16(i16)
declare void @use(ptr)
define void @runtime.initAll() unnamed_addr {
entry:
call void @main.init()
ret void
}
define void @main() unnamed_addr {
entry:
; print(uintSliceSrc[0])
%uint8SliceSrc.buf = load ptr, ptr @main.uint8SliceSrc
%uint8SliceSrc.val = load i8, ptr %uint8SliceSrc.buf
call void @runtime.printuint8(i8 %uint8SliceSrc.val)
; print(uintSliceDst[0])
%uint8SliceDst.buf = load ptr, ptr @main.uint8SliceDst
%uint8SliceDst.val = load i8, ptr %uint8SliceDst.buf
call void @runtime.printuint8(i8 %uint8SliceDst.val)
; print(int16SliceSrc[0])
%int16SliceSrc.buf = load ptr, ptr @main.int16SliceSrc
%int16SliceSrc.val = load i16, ptr %int16SliceSrc.buf
call void @runtime.printint16(i16 %int16SliceSrc.val)
; print(int16SliceDst[0])
%int16SliceDst.buf = load ptr, ptr @main.int16SliceDst
%int16SliceDst.val = load i16, ptr %int16SliceDst.buf
call void @runtime.printint16(i16 %int16SliceDst.val)
; print(sliceDstUntaint[0])
%sliceDstUntaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstUntaint.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstUntaint.val)
; print(sliceDstTaint[0])
%sliceDstTaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstTaint.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstTaint.val)
; print(sliceDstExternal1[0])
%sliceDstExternal1.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal1.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
; print(sliceDstExternal2[0])
%sliceDstExternal2.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal2.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
ret void
}
define internal void @main.init() unnamed_addr {
entry:
; equivalent of:
; uint8SliceDst = make([]uint8, len(uint8SliceSrc))
%uint8SliceSrc = load { ptr, i64, i64 }, ptr @main.uint8SliceSrc
%uint8SliceSrc.len = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 1
%uint8SliceDst.buf = call ptr @runtime.alloc(i64 %uint8SliceSrc.len, ptr null)
%0 = insertvalue { ptr, i64, i64 } undef, ptr %uint8SliceDst.buf, 0
%1 = insertvalue { ptr, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
%2 = insertvalue { ptr, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
store { ptr, i64, i64 } %2, ptr @main.uint8SliceDst
; equivalent of:
; copy(uint8SliceDst, uint8SliceSrc)
%uint8SliceSrc.buf = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 0
%copy.n = call i64 @runtime.sliceCopy(ptr %uint8SliceDst.buf, ptr %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
; equivalent of:
; int16SliceDst = make([]int16, len(int16SliceSrc))
%int16SliceSrc = load { ptr, i64, i64 }, ptr @main.int16SliceSrc
%int16SliceSrc.len = extractvalue { ptr, i64, i64 } %int16SliceSrc, 1
%int16SliceSrc.len.bytes = mul i64 %int16SliceSrc.len, 2
%int16SliceDst.buf = call ptr @runtime.alloc(i64 %int16SliceSrc.len.bytes, ptr null)
%3 = insertvalue { ptr, i64, i64 } undef, ptr %int16SliceDst.buf, 0
%4 = insertvalue { ptr, i64, i64 } %3, i64 %int16SliceSrc.len, 1
%5 = insertvalue { ptr, i64, i64 } %4, i64 %int16SliceSrc.len, 2
store { ptr, i64, i64 } %5, ptr @main.int16SliceDst
; equivalent of:
; copy(int16SliceDst, int16SliceSrc)
%int16SliceSrc.buf = extractvalue { ptr, i64, i64 } %int16SliceSrc, 0
%copy.n2 = call i64 @runtime.sliceCopy(ptr %int16SliceDst.buf, ptr %int16SliceSrc.buf, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
; Copy slice that has a known value.
%copy.n3 = call i64 @runtime.sliceCopy(ptr @main.sliceDstUntaint.buf, ptr @main.sliceSrcUntaint.buf, i64 2, i64 2, i64 1)
; Copy slice that might have been modified by the external @use call.
; This is a fix for https://github.com/tinygo-org/tinygo/issues/3890.
call void @use(ptr @main.sliceSrcTaint.buf)
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
; Test that copying from or into external buffers works correctly.
; These copy operations must be done at runtime.
; https://github.com/tinygo-org/tinygo/issues/4895
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
ret void
}
+42
View File
@@ -0,0 +1,42 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal1.buf = external global [2 x i8]
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
@main.sliceDstExternal2.buf = external global [2 x i8]
declare i64 @runtime.sliceCopy(ptr, ptr, i64, i64, i64) unnamed_addr
declare void @runtime.printuint8(i8) local_unnamed_addr
declare void @runtime.printint16(i16) local_unnamed_addr
declare void @use(ptr) local_unnamed_addr
define void @runtime.initAll() unnamed_addr {
entry:
call void @use(ptr @main.sliceSrcTaint.buf)
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
ret void
}
define void @main() unnamed_addr {
entry:
call void @runtime.printuint8(i8 3)
call void @runtime.printuint8(i8 3)
call void @runtime.printint16(i16 5)
call void @runtime.printint16(i16 5)
call void @runtime.printuint8(i8 97)
%sliceDstTaint.val = load i8, ptr @main.sliceDstTaint.buf, align 1
call void @runtime.printuint8(i8 %sliceDstTaint.val)
%sliceDstExternal1.val = load i8, ptr @main.sliceDstExternal1.buf, align 1
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
%sliceDstExternal2.val = load i8, ptr @main.sliceDstExternal2.buf, align 1
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
ret void
}
+27 -51
View File
@@ -229,37 +229,33 @@ func needsSyscallPackage(buildTags []string) bool {
// means use the TinyGo version.
func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths := map[string]bool{
"": true,
"crypto/": true,
"crypto/rand/": false,
"crypto/tls/": false,
"crypto/x509/": true,
"crypto/x509/internal/": true,
"crypto/x509/internal/macos/": false,
"device/": false,
"examples/": false,
"internal/": true,
"internal/abi/": false,
"internal/binary/": false,
"internal/bytealg/": false,
"internal/cm/": false,
"internal/futex/": false,
"internal/fuzz/": false,
"internal/itoa/": false,
"internal/reflectlite/": false,
"internal/gclayout": false,
"internal/task/": false,
"internal/wasi/": false,
"machine/": false,
"net/": true,
"net/http/": false,
"os/": true,
"reflect/": false,
"runtime/": false,
"sync/": true,
"testing/": true,
"tinygo/": false,
"unique/": false,
"": true,
"crypto/": true,
"crypto/rand/": false,
"crypto/tls/": false,
"device/": false,
"examples/": false,
"internal/": true,
"internal/abi/": false,
"internal/binary/": false,
"internal/bytealg/": false,
"internal/cm/": false,
"internal/futex/": false,
"internal/fuzz/": false,
"internal/reflectlite/": false,
"internal/gclayout": false,
"internal/task/": false,
"internal/wasi/": false,
"machine/": false,
"net/": true,
"net/http/": false,
"os/": true,
"reflect/": false,
"runtime/": false,
"sync/": true,
"testing/": true,
"tinygo/": false,
"unique/": false,
}
if goMinor >= 19 {
@@ -268,31 +264,11 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths["crypto/internal/boring/sig/"] = false
}
if goMinor >= 26 {
// Go 1.26 added a CPU jitter entropy source for FIPS 140-3 that
// allocates a 32 MiB global buffer (ScratchBuffer [1<<25]byte).
// This is fine on systems with virtual memory, but causes RAM
// overflow on microcontrollers. Replace with a zero-size stub
// since TinyGo targets never use FIPS jitter entropy.
paths["crypto/internal/entropy/"] = true
paths["crypto/internal/entropy/v1.0.0/"] = false
}
if needsSyscallPackage {
paths["syscall/"] = true // include syscall/js
paths["internal/syscall/"] = true
paths["internal/syscall/unix/"] = false
}
if goMinor >= 26 {
// Go 1.26 added SWAR optimizations to unicode/utf8 that use
// constants assuming at least 32-bit uintptr. TinyGo supports
// 16-bit targets (AVR) where these constants overflow, so we
// provide a patched version.
paths["unicode/"] = true
paths["unicode/utf8/"] = false
}
return paths
}
+41 -78
View File
@@ -304,29 +304,6 @@ func (p *Program) Sorted() []*Package {
return p.sorted
}
// StripVarInitializer removes the package-level initializer for the named
// variable from the type info. This prevents go/ssa from emitting an init
// store for it, leaving the global zero-initialized in the IR. An external
// value (e.g. from -ldflags -X via makeGlobalsModule) can then be linked in
// at final link time without any runtime init overwriting it.
//
// Must be called after Parse() (typechecking populates InitOrder) and before
// LoadSSA() (which consumes InitOrder to build the package init function).
//
// Only 1:1 var initializers (var x = expr) are matched. Multi-variable
// initializers (var x, y = f()) are left untouched.
func (p *Package) StripVarInitializer(name string) {
n := 0
for _, init := range p.info.InitOrder {
if len(init.Lhs) == 1 && init.Lhs[0].Name() == name {
continue // drop this initializer
}
p.info.InitOrder[n] = init
n++
}
p.info.InitOrder = p.info.InitOrder[:n]
}
// MainPkg returns the last package in the Sorted() slice. This is the main
// package of the program.
func (p *Program) MainPkg() *Package {
@@ -572,7 +549,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
}
// Look for //go:embed comments.
var allPatterns []embedPattern
var allPatterns []string
for _, comment := range doc.List {
if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") {
continue
@@ -600,7 +577,21 @@ func (p *Package) extractEmbedLines(addError func(error)) {
})
continue
}
allPatterns = append(allPatterns, patterns...)
for _, pattern := range patterns {
// Check that the pattern is well-formed.
// It must be valid: the Go toolchain has already
// checked for invalid patterns. But let's check
// anyway to be sure.
if _, err := path.Match(pattern, ""); err != nil {
addError(types.Error{
Fset: p.program.fset,
Pos: comment.Pos(),
Msg: "invalid pattern syntax",
})
continue
}
allPatterns = append(allPatterns, pattern)
}
}
if len(allPatterns) != 0 {
@@ -633,8 +624,8 @@ func (p *Package) extractEmbedLines(addError func(error)) {
// Match all //go:embed patterns against the embed files
// provided by `go list`.
for _, name := range p.EmbedFiles {
for _, ep := range allPatterns {
if ep.Match(name) {
for _, pattern := range allPatterns {
if matchPattern(pattern, name) {
p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{
Name: name,
NeedsData: byteSlice,
@@ -650,37 +641,13 @@ func (p *Package) extractEmbedLines(addError func(error)) {
}
}
// embedPattern represents a valid //go:embed pattern.
// See: https://pkg.go.dev/embed#hdr-Directives
type embedPattern struct {
pattern string // glob pattern without "all:" prefix
includeHidden bool // true if "all:" prefix was present
}
// newEmbedPattern parses and validates a //go:embed pattern.
// The "all:" prefix (if present) is stripped and reflected in includeHidden.
// Returns an error if the pattern syntax is invalid.
func newEmbedPattern(s string) (embedPattern, error) {
ep := embedPattern{pattern: s}
if strings.HasPrefix(s, "all:") {
ep.pattern = s[4:]
ep.includeHidden = true
}
if _, err := path.Match(ep.pattern, ""); err != nil {
return embedPattern{}, err
}
return ep, nil
}
// Match returns true if (and only if) the pattern matches the given filename.
// The pattern could also match a parent directory of name, in which case hidden
// files do not match (unless includeHidden is true).
func (ep embedPattern) Match(name string) bool {
pattern := ep.pattern
includeHidden := ep.includeHidden
// matchPattern returns true if (and only if) the given pattern would match the
// filename. The pattern could also match a parent directory of name, in which
// case hidden files do not match.
func matchPattern(pattern, name string) bool {
// Match this file.
if matched, _ := path.Match(pattern, name); matched {
matched, _ := path.Match(pattern, name)
if matched {
return true
}
@@ -694,20 +661,17 @@ func (ep embedPattern) Match(name string) bool {
dir = path.Clean(dir)
if matched, _ := path.Match(pattern, dir); matched {
// Pattern matches the directory.
if !includeHidden {
suffix := name[len(dir):]
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
// Pattern matches a hidden file.
// Hidden files are included when listed directly as a
// pattern, or when the "all:" prefix is used, but not
// when they are part of a directory tree without "all:".
// Source:
// > If a pattern names a directory, all files in the
// > subtree rooted at that directory are embedded
// > (recursively), except that files with names beginning
// > with . or _ are excluded.
return false
}
suffix := name[len(dir):]
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
// Pattern matches a hidden file.
// Hidden files are included when listed directly as a
// pattern, but not when they are part of a directory tree.
// Source:
// > If a pattern names a directory, all files in the
// > subtree rooted at that directory are embedded
// > (recursively), except that files with names beginning
// > with . or _ are excluded.
return false
}
return true
}
@@ -716,12 +680,11 @@ func (ep embedPattern) Match(name string) bool {
// parseGoEmbed is like strings.Fields but for a //go:embed line. It parses
// regular fields and quoted fields (that may contain spaces).
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPattern, err error) {
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, err error) {
args = strings.TrimSpace(args)
initialLen := len(args)
for args != "" {
patternPos := pos + token.Pos(initialLen-len(args))
var pattern string
switch args[0] {
case '`', '"', '\\':
// Parse the next pattern using the Go scanner.
@@ -740,7 +703,8 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPatt
Msg: "invalid quoted string in //go:embed",
}
}
pattern = constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
pattern := constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
patterns = append(patterns, pattern)
args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace)
default:
// The value is just a regular value.
@@ -749,18 +713,17 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPatt
if index < 0 {
index = len(args)
}
pattern = args[:index]
pattern := args[:index]
patterns = append(patterns, pattern)
args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace)
}
ep, err := newEmbedPattern(pattern)
if err != nil {
if _, err := path.Match(patterns[len(patterns)-1], ""); err != nil {
return nil, types.Error{
Fset: p.program.fset,
Pos: patternPos,
Msg: "invalid pattern syntax",
}
}
patterns = append(patterns, ep)
}
return patterns, nil
}

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