Compare commits

..

1 Commits

Author SHA1 Message Date
Nia Waldvogel 80c89809a9 machine: fix usb truncation?
Remove the sendUSBPacket maxLen param because this greatly confused the compiler.
It also fixes a bug where the length provided to the hardware may not match the length of the packet.
sendUSBPacket now panics if the sent packet is too big.

I also fixed some of the string descriptor logic where we could create a packet without fully populating it.

RP2* systems might require some more work since they are implemented very differently?
I don't have any of those to test with yet, so maybe someone can deal with them in a seperate PR?
2025-12-30 15:51:27 -05:00
325 changed files with 4101 additions and 19548 deletions
+119
View File
@@ -0,0 +1,119 @@
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-oldest:
# This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass.
docker:
- image: golang:1.22-bullseye
steps:
- test-linux:
llvm: "15"
resource_class: large
test-newest:
# This tests the latest supported LLVM version when linking against system
# libraries.
docker:
- image: golang:1.25-bullseye
steps:
- test-linux:
llvm: "20"
resource_class: large
workflows:
test-all:
jobs:
- test-oldest
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
# - test-newest
+1
View File
@@ -1,4 +1,5 @@
build/ build/
llvm-*/ llvm-*/
.github .github
.circleci
+16 -12
View File
@@ -31,7 +31,7 @@ jobs:
run: | run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
@@ -40,10 +40,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-${{ matrix.os }}-v1 key: llvm-source-20-${{ matrix.os }}-v1
@@ -57,7 +57,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -68,7 +68,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-${{ matrix.os }}-v2 key: llvm-build-20-${{ matrix.os }}-v2
@@ -85,7 +85,7 @@ jobs:
make llvm-build make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
@@ -101,11 +101,16 @@ jobs:
- name: Make release artifact - name: Make release artifact
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact - 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: with:
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
archive: false
- name: Smoke tests - name: Smoke tests
run: make smoketest TINYGO=$(PWD)/build/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew: test-macos-homebrew:
@@ -116,7 +121,7 @@ jobs:
version: [16, 17, 18, 19, 20] version: [16, 17, 18, 19, 20]
steps: steps:
- name: Set up Homebrew - name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@main uses: Homebrew/actions/setup-homebrew@master
- name: Fix Python symlinks - name: Fix Python symlinks
run: | run: |
# Github runners have broken symlinks, so relink # Github runners have broken symlinks, so relink
@@ -125,13 +130,12 @@ jobs:
- name: Install LLVM - name: Install LLVM
run: | run: |
brew install llvm@${{ matrix.version }} brew install llvm@${{ matrix.version }}
brew link llvm@${{ matrix.version }}
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }} run: go install -tags=llvm${{ matrix.version }}
+6 -6
View File
@@ -31,14 +31,14 @@ jobs:
sudo rm -rf /usr/local/share/boost sudo rm -rf /usr/local/share/boost
df -h df -h
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: recursive submodules: recursive
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
tinygo/tinygo-dev tinygo/tinygo-dev
@@ -47,18 +47,18 @@ jobs:
type=sha,format=long type=sha,format=long
type=raw,value=latest type=raw,value=latest
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry - name: Log in to Github Container Registry
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: . context: .
push: true push: true
+48 -58
View File
@@ -18,12 +18,12 @@ jobs:
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.26-alpine image: golang:1.25-alpine
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Install apk dependencies - name: Install apk dependencies
# tar: needed for actions/cache@v5 # tar: needed for actions/cache@v4
# git+openssh: needed for checkout (I think?) # git+openssh: needed for checkout (I think?)
# ruby: needed to install fpm # 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 mold
@@ -31,24 +31,24 @@ jobs:
# We're not on a multi-user machine, so this is safe. # We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE" run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
id: version id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT" run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Cache Go - name: Cache Go
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-linux-alpine-v2-${{ hashFiles('go.mod') }} key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
path: | path: |
~/.cache/go-build ~/.cache/go-build
~/go/pkg/mod ~/go/pkg/mod
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-alpine-v2 key: llvm-source-20-linux-alpine-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -59,7 +59,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -70,10 +70,10 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-alpine-v2 key: llvm-build-20-linux-alpine-v1
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -88,16 +88,16 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-alpine-v2 key: binaryen-linux-alpine-v1
path: build/wasm-opt path: build/wasm-opt
- name: Build Binaryen - name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true' if: steps.cache-binaryen.outputs.cache-hit != 'true'
@@ -118,31 +118,26 @@ jobs:
make release deb -j3 STATIC=1 make release deb -j3 STATIC=1
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
- name: "Publish release artifact: tarball" - name: Publish release artifact
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz name: linux-amd64-double-zipped-${{ steps.version.outputs.version }}
path: /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz path: |
archive: false /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
- name: "Publish release artifact: Debian package" /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
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
test-linux-build: test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests. # Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build-linux needs: build-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -151,9 +146,9 @@ jobs:
- name: Install wasm-tools - name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Download release artifact - name: Download release artifact
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: 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 - name: Extract release tarball
run: | run: |
mkdir -p ~/lib mkdir -p ~/lib
@@ -169,7 +164,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Install apt dependencies - name: Install apt dependencies
@@ -186,10 +181,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '18'
- name: Install wasmtime - name: Install wasmtime
@@ -199,7 +194,7 @@ jobs:
- name: Setup `wasm-tools` - name: Setup `wasm-tools`
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-asserts-v1 key: llvm-source-20-linux-asserts-v1
@@ -213,7 +208,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -224,7 +219,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-asserts-v1 key: llvm-build-20-linux-asserts-v1
@@ -240,13 +235,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-asserts-v1 key: binaryen-linux-asserts-v1
@@ -289,7 +284,7 @@ jobs:
needs: build-linux needs: build-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Get TinyGo version - name: Get TinyGo version
id: version id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT" run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
@@ -303,10 +298,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-v1 key: llvm-source-20-linux-v1
@@ -320,7 +315,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -331,7 +326,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-${{ matrix.goarch }}-v1 key: llvm-build-20-linux-${{ matrix.goarch }}-v1
@@ -349,13 +344,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-${{ matrix.goarch }}-v4 key: binaryen-linux-${{ matrix.goarch }}-v4
@@ -375,9 +370,9 @@ jobs:
run: | run: |
make CROSS=${{ matrix.toolchain }} make CROSS=${{ matrix.toolchain }}
- name: Download amd64 release - name: Download amd64 release
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: 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 - name: Extract amd64 release
run: | run: |
mkdir -p build/release mkdir -p build/release
@@ -389,17 +384,12 @@ jobs:
- name: Create ${{ matrix.goarch }} release - name: Create ${{ matrix.goarch }} release
run: | run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }} make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
- name: "Publish release artifact: tarball" - name: Publish release artifact
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz path: |
archive: false /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
- name: "Publish release artifact: Debian package" /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
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
+5 -5
View File
@@ -25,14 +25,14 @@ jobs:
contents: read contents: read
steps: steps:
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: recursive submodules: recursive
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
tinygo/llvm-20 tinygo/llvm-20
@@ -46,13 +46,13 @@ jobs:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry - name: Log in to Github Container Registry
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
target: tinygo-llvm-build target: tinygo-llvm-build
context: . context: .
+4 -4
View File
@@ -21,12 +21,12 @@ jobs:
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668 # See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
run: sudo apt-get remove llvm-18 run: sudo apt-get remove llvm-18
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Pull musl, bdwgc - name: Pull musl, bdwgc
run: | run: |
git submodule update --init lib/musl lib/bdwgc git submodule update --init lib/musl lib/bdwgc
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-nix-v1 key: llvm-source-20-linux-nix-v1
@@ -36,13 +36,13 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: | path: |
llvm-project/compiler-rt llvm-project/compiler-rt
- uses: cachix/install-nix-action@v31 - uses: cachix/install-nix-action@v22
- name: Test - name: Test
run: | run: |
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo" nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
run: | run: |
echo "$HOME/go/bin" >> $GITHUB_PATH echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
fetch-depth: 0 # fetch all history (no sparse checkout) fetch-depth: 0 # fetch all history (no sparse checkout)
submodules: true submodules: true
- name: Install apt dependencies - name: Install apt dependencies
run: ./.github/workflows/sizediff-install-pkgs.sh run: ./.github/workflows/sizediff-install-pkgs.sh
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-sizediff-v1 key: llvm-source-20-sizediff-v1
@@ -37,7 +37,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache Go - name: Cache Go
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }} key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
path: | path: |
+47 -31
View File
@@ -24,13 +24,14 @@ jobs:
maximum-size: 24GB maximum-size: 24GB
disk-root: "C:" disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true
scoop install ninja binaryen scoop install ninja binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
@@ -40,10 +41,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Restore cached LLVM source - name: Restore cached LLVM source
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-windows-v1 key: llvm-source-20-windows-v1
@@ -57,7 +58,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save cached 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' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -68,7 +69,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore cached LLVM build - name: Restore cached LLVM build
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-windows-v2 key: llvm-build-20-windows-v2
@@ -85,21 +86,20 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save cached LLVM build - name: Save cached LLVM build
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Go cache - name: Cache Go cache
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-windows-v2-${{ hashFiles('go.mod') }} key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
path: | path: |
C:/Users/runneradmin/AppData/Local/go-build C:/Users/runneradmin/AppData/Local/go-build
C:/Users/runneradmin/go/pkg/mod C:/Users/runneradmin/go/pkg/mod
- name: Install wasmtime - name: Install wasmtime
run: | run: |
scoop config use_external_7zip true
scoop install wasmtime@29.0.1 scoop install wasmtime@29.0.1
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make -j3 gen-device
@@ -114,11 +114,16 @@ jobs:
working-directory: build/release working-directory: build/release
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo
- name: Publish release artifact - 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: 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 path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
archive: false
smoke-test-windows: smoke-test-windows:
runs-on: windows-2022 runs-on: windows-2022
@@ -131,24 +136,28 @@ jobs:
maximum-size: 24GB maximum-size: 24GB
disk-root: "C:" disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true
scoop install binaryen scoop install binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ 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 - name: Smoke tests
shell: bash shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -164,18 +173,21 @@ jobs:
maximum-size: 24GB maximum-size: 24GB
disk-root: "C:" disk-root: "C:"
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ 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 - name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -190,23 +202,27 @@ jobs:
maximum-size: 24GB maximum-size: 24GB
disk-root: "C:" disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true scoop install binaryen && scoop install wasmtime@29.0.1
scoop install binaryen wasmtime@29.0.1
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.2' go-version: '1.25.5'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ 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 - name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
-157
View File
@@ -1,160 +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 0.40.1
--- ---
* **machine** * **machine**
+2 -2
View File
@@ -1,5 +1,5 @@
# tinygo-llvm stage obtains the llvm source for TinyGo # tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.26 AS tinygo-llvm FROM golang:1.25 AS tinygo-llvm
RUN apt-get update && \ 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-17 ninja-build && \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without # tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc). # all the build tools etc).
FROM golang:1.26 AS tinygo-compiler FROM golang:1.25 AS tinygo-compiler
# Copy tinygo build. # Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+8 -71
View File
@@ -289,13 +289,13 @@ WASM_TOOLS_MODULE=go.bytecodealliance.org
.PHONY: wasi-syscall .PHONY: wasi-syscall
wasi-syscall: wasi-cm wasi-syscall: wasi-cm
rm -rf ./src/internal/wasi/* 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 # Copy package cm into src/internal/cm
.PHONY: wasi-cm .PHONY: wasi-cm
wasi-cm: wasi-cm:
rm -rf ./src/internal/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. # Check for Node.js used during WASM tests.
MIN_NODEJS_VERSION=18 MIN_NODEJS_VERSION=18
@@ -339,17 +339,14 @@ TEST_PACKAGES_FAST = \
embed/internal/embedtest \ embed/internal/embedtest \
encoding \ encoding \
encoding/ascii85 \ encoding/ascii85 \
errors \
encoding/asn1 \ encoding/asn1 \
encoding/base32 \ encoding/base32 \
encoding/base64 \ encoding/base64 \
encoding/csv \ encoding/csv \
encoding/hex \ encoding/hex \
expvar \
go/ast \ go/ast \
go/format \ go/format \
go/scanner \ go/scanner \
go/token \
go/version \ go/version \
hash \ hash \
hash/adler32 \ hash/adler32 \
@@ -362,7 +359,6 @@ TEST_PACKAGES_FAST = \
math/cmplx \ math/cmplx \
net/http/internal/ascii \ net/http/internal/ascii \
net/mail \ net/mail \
net/url \
os \ os \
path \ path \
reflect \ reflect \
@@ -383,7 +379,6 @@ TEST_PACKAGES_FAST = \
# crypto/des fails on wasi, needs panic()/recover() # crypto/des fails on wasi, needs panic()/recover()
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic # crypto/hmac fails on wasi, it exits with a "slice out of range" panic
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows # debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# encoding/xml takes a minute on linux and gives a stack overflow on wasi
# image requires recover(), which is not yet supported on wasi # image requires recover(), which is not yet supported on wasi
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi # io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# mime: fail on wasi; neds panic()/recover() # mime: fail on wasi; neds panic()/recover()
@@ -401,13 +396,11 @@ TEST_PACKAGES_FAST = \
TEST_PACKAGES_LINUX := \ TEST_PACKAGES_LINUX := \
archive/zip \ archive/zip \
compress/flate \ compress/flate \
context \
crypto/aes \ crypto/aes \
crypto/des \ crypto/des \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
encoding/xml \
image \ image \
io/ioutil \ io/ioutil \
mime \ mime \
@@ -444,7 +437,6 @@ TEST_PACKAGES_NONWASM = \
crypto/ecdsa \ crypto/ecdsa \
debug/macho \ debug/macho \
embed/internal/embedtest \ embed/internal/embedtest \
expvar \
go/format \ go/format \
os \ os \
testing \ testing \
@@ -488,7 +480,7 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false TEST_IOFS := false
endif endif
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic|TestAsValidation' TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
TEST_ADDITIONAL_FLAGS ?= TEST_ADDITIONAL_FLAGS ?=
# Test known-working standard library packages. # Test known-working standard library packages.
@@ -634,7 +626,7 @@ smoketest: testchdir
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org # test simulated boards on play.tinygo.org
ifneq ($(WASM), 0) 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 @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1 GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
@@ -652,8 +644,6 @@ ifneq ($(WASM), 0)
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1 GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=xiao_esp32s3 examples/blinky1
@$(MD5SUM) test.wasm
endif endif
# test all targets/boards # test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@@ -824,10 +814,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo $(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
@$(MD5SUM) test.hex @$(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 # test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -887,24 +873,18 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial $(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
@$(MD5SUM) test.hex @$(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 endif
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm $(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest $(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
@$(MD5SUM) test.hex @$(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 @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
@$(MD5SUM) test.hex @$(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 @$(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 @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -916,25 +896,13 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1 $(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
ifneq ($(XTENSA), 0) 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 $(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
@$(MD5SUM) test.bin @$(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 $(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest $(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
@@ -947,39 +915,9 @@ ifneq ($(XTENSA), 0)
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest $(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
# xiao-esp32s3
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1 $(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
@$(MD5SUM) test.bin @$(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 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 $(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest $(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
@@ -992,7 +930,6 @@ endif
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest $(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@@ -1186,7 +1123,7 @@ endif
.PHONY: tools .PHONY: tools
tools: tools:
go generate -tags tools ./ cd internal/tools && go generate -tags tools ./
LINTDIRS=src/os/ src/reflect/ LINTDIRS=src/os/ src/reflect/
.PHONY: lint .PHONY: lint
+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. TinyGo includes portions of the Go standard library.
Copyright 2009 The Go Authors. All rights reserved. Copyright (c) 2009-2024 The Go Authors. All rights reserved.
See https://github.com/golang/go/blob/master/LICENSE for license information.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with 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. 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 # 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. 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. 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 ## Embedded
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED: 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 ```shell
tinygo flash -target arduino-uno examples/blinky1 tinygo flash -target arduino examples/blinky1
``` ```
## WebAssembly ## 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+: You can also use the same syntax as Go 1.24+:
```shell ```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 ## Installation
@@ -77,7 +74,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
### Embedded ### 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/ For more information, please see https://tinygo.org/docs/reference/microcontrollers/
@@ -142,7 +139,7 @@ Non-goals:
## Why this project exists ## 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) -- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799)
+6 -40
View File
@@ -19,7 +19,6 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -255,18 +254,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path() 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 // Create the *ssa.Program. This does not yet build the entire SSA of the
// program so it's pretty fast and doesn't need to be parallelized. // program so it's pretty fast and doesn't need to be parallelized.
program := lprogram.LoadSSA() program := lprogram.LoadSSA()
@@ -294,13 +281,9 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
allFiles[file.Name] = append(allFiles[file.Name], file) allFiles[file.Name] = append(allFiles[file.Name], file)
} }
} }
// Sort embedded files by name to maintain output determinism. for name, files := range allFiles {
embedNames := make([]string, 0, len(allFiles)) name := name
for _, files := range allFiles { files := files
embedNames = append(embedNames, files[0].Name)
}
slices.Sort(embedNames)
for _, name := range embedNames {
job := &compileJob{ job := &compileJob{
description: "make object file for " + name, description: "make object file for " + name,
run: func(job *compileJob) error { run: func(job *compileJob) error {
@@ -315,7 +298,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
sum := sha256.Sum256(data) sum := sha256.Sum256(data)
hexSum := hex.EncodeToString(sum[:16]) hexSum := hex.EncodeToString(sum[:16])
for _, file := range allFiles[name] { for _, file := range files {
file.Size = uint64(len(data)) file.Size = uint64(len(data))
file.Hash = hexSum file.Hash = hexSum
if file.NeedsData { if file.NeedsData {
@@ -489,7 +472,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if pkgInit.IsNil() { if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path()) 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 { if err != nil {
return err return err
} }
@@ -558,23 +541,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil { if err != nil {
return fmt.Errorf("failed to load bitcode file: %w", err) 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) err = llvm.LinkModules(mod, pkgMod)
if err != nil { if err != nil {
return fmt.Errorf("failed to link module: %w", err) return fmt.Errorf("failed to link module: %w", 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 // 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. // optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error { 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 { if err != nil {
return err return err
} }
+1 -1
View File
@@ -107,7 +107,7 @@ struct AssemblerInvocation {
EmitDwarfUnwindType EmitDwarfUnwind; EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries. // 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) LLVM_PREFERRED_TYPE(bool)
unsigned EmitCompactUnwindNonCanonical : 1; unsigned EmitCompactUnwindNonCanonical : 1;
+1 -1
View File
@@ -26,7 +26,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
// Version range supported by TinyGo. // Version range supported by TinyGo.
const minorMin = 19 const minorMin = 19
const minorMax = 26 const minorMax = 25
// Check that we support this Go toolchain version. // Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion() gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
+2 -16
View File
@@ -167,9 +167,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// double. // double.
args = append(args, "-mdouble=64") args = append(args, "-mdouble=64")
case "riscv32": case "riscv32":
args = append(args, "-march="+riscvMarch(config, "rv32imac"), "-fforce-enable-int128") args = append(args, "-march=rv32imac", "-fforce-enable-int128")
case "riscv64": case "riscv64":
args = append(args, "-march="+riscvMarch(config, "rv64gc")) args = append(args, "-march=rv64gc")
case "mips": case "mips":
args = append(args, "-fno-pic") args = append(args, "-fno-pic")
} }
@@ -298,17 +298,3 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
once.Do(unlock) once.Do(unlock)
}, nil }, 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)) libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator))
parts := strings.SplitN(libPath, string(os.PathSeparator), 2) parts := strings.SplitN(libPath, string(os.PathSeparator), 2)
packagePath = "C " + parts[0] packagePath = "C " + parts[0]
if len(parts) > 1 { filename = parts[1]
filename = parts[1]
} else {
filename = parts[0]
}
} else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) { } else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) {
packagePath = "C compiler-rt" packagePath = "C compiler-rt"
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator)) filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
+2 -2
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. // This is a small number of very diverse targets that we want to test.
tests := []sizeTest{ tests := []sizeTest{
// microcontrollers // microcontrollers
{"hifive1b", "examples/echo", 3680, 280, 0, 2252}, {"hifive1b", "examples/echo", 3668, 280, 0, 2244},
{"microbit", "examples/serial", 2694, 342, 8, 2248}, {"microbit", "examples/serial", 2694, 342, 8, 2248},
{"wioterminal", "examples/pininterrupt", 7074, 1510, 120, 7248}, {"wioterminal", "examples/pininterrupt", 6833, 1491, 120, 6888},
// TODO: also check wasm. Right now this is difficult, because // TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the // wasm binaries are run through wasm-opt and therefore the
+1 -1
View File
@@ -28,7 +28,7 @@ func RunTool(tool string, args ...string) error {
var cflag *C.char var cflag *C.char
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag))) buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
defer C.free(buf) 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 { for i, flag := range args {
cflag := C.CString(flag) cflag := C.CString(flag)
cflags[i] = cflag cflags[i] = cflag
+1 -5
View File
@@ -122,16 +122,12 @@ func parseLLDErrors(text string) error {
parsedError = true parsedError = true
line, _ := strconv.Atoi(matches[3]) line, _ := strconv.Atoi(matches[3])
// TODO: detect common mistakes like -gc=none? // 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{ linkErrors = append(linkErrors, scanner.Error{
Pos: token.Position{ Pos: token.Position{
Filename: matches[2], Filename: matches[2],
Line: line, 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. // 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)))) cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0))))
defer C.free(cmdargsC) defer C.free(cmdargsC)
cmdargs := unsafe.Slice((**C.char)(cmdargsC), len(cflags)) cmdargs := (*[1 << 16]*C.char)(cmdargsC)
for i, cflag := range cflags { for i, cflag := range cflags {
s := C.CString(cflag) s := C.CString(cflag)
cmdargs[i] = s 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. // Sanity check. This should (hopefully) never trigger.
panic("libclang: file contents was not loaded") 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. // Hash the contents if it isn't hashed yet.
if _, ok := f.visitedFiles[path]; !ok { 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. // now by reading the file from libclang.
var size C.size_t var size C.size_t
sourcePtr := C.clang_getFileContents(tu, file, &size) 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} lines := []int{0}
for i := 0; i < len(source)-1; i++ { for i := 0; i < len(source)-1; i++ {
if source[i] == '\n' { if source[i] == '\n' {
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo 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,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include
#cgo freebsd CFLAGS: -I/usr/local/llvm19/include #cgo freebsd CFLAGS: -I/usr/local/llvm19/include
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo 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,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
#cgo freebsd CFLAGS: -I/usr/local/llvm20/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-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?plt`), re(`-f(no-)?plt`),
re(`-f(no-)?rtti`), re(`-f(no-)?rtti`),
re(`-f(no-)?short-enums`),
re(`-f(no-)?split-stack`), re(`-f(no-)?split-stack`),
re(`-f(no-)?stack-(.+)`), re(`-f(no-)?stack-(.+)`),
re(`-f(no-)?strict-aliasing`), re(`-f(no-)?strict-aliasing`),
+1 -1
View File
@@ -536,7 +536,7 @@ func (c *Config) Programmer() (method, openocdInterface string) {
case "": case "":
// No configuration supplied. // No configuration supplied.
return c.Target.FlashMethod, c.Target.OpenOCDInterface return c.Target.FlashMethod, c.Target.OpenOCDInterface
case "openocd", "msd", "command", "adb": case "openocd", "msd", "command":
// The -programmer flag only specifies the flash method. // The -programmer flag only specifies the flash method.
return c.Options.Programmer, c.Target.OpenOCDInterface return c.Options.Programmer, c.Target.OpenOCDInterface
case "bmp": case "bmp":
+39 -40
View File
@@ -21,46 +21,45 @@ var (
// usually passed from the command line, but can also be passed in environment // usually passed from the command line, but can also be passed in environment
// variables for example. // variables for example.
type Options struct { type Options struct {
GOOS string // environment variable GOOS string // environment variable
GOARCH string // environment variable GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm) GOARM string // environment variable (only used with GOARCH=arm)
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle) 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 Directory string // working dir, leave it unset to use the current working dir
Target string Target string
BuildMode string // -buildmode flag BuildMode string // -buildmode flag
Opt string Opt string
GC string GC string
PanicStrategy string PanicStrategy string
Scheduler string Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined) StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string Serial string
Work bool // -work flag to print temporary build directory Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration InterpTimeout time.Duration
InterpMaxLoopIterations int PrintIR bool
PrintIR bool DumpSSA bool
DumpSSA bool VerifyIR bool
VerifyIR bool SkipDWARF bool
SkipDWARF bool PrintCommands func(cmd string, args ...string) `json:"-"`
PrintCommands func(cmd string, args ...string) `json:"-"` Semaphore chan struct{} `json:"-"` // -p flag controls cap
Semaphore chan struct{} `json:"-"` // -p flag controls cap Debug bool
Debug bool Nobounds bool
Nobounds bool PrintSizes string
PrintSizes string PrintAllocs *regexp.Regexp // regexp string
PrintAllocs *regexp.Regexp // regexp string PrintStacks bool
PrintStacks bool Tags []string
Tags []string GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value TestConfig TestConfig
TestConfig TestConfig Programmer string
Programmer string OpenOCDCommands []string
OpenOCDCommands []string LLVMFeatures string
LLVMFeatures string Monitor bool
Monitor bool BaudRate int
BaudRate int Timeout time.Duration
Timeout time.Duration WITPackage string // pass through to wasm-tools component embed invocation
WITPackage string // pass through to wasm-tools component embed invocation WITWorld string // pass through to wasm-tools component embed -w option
WITWorld string // pass through to wasm-tools component embed -w option ExtLDFlags []string
ExtLDFlags []string GoCompatibility bool // enable to check for Go version compatibility
GoCompatibility bool // enable to check for Go version compatibility
} }
// Verify performs a validation on the given options, raising an error if options are not valid. // Verify performs a validation on the given options, raising an error if options are not valid.
-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 // https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct { type TargetSpec struct {
Inherits []string `json:"inherits,omitempty"` 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"` Triple string `json:"llvm-target,omitempty"`
CPU string `json:"cpu,omitempty"` CPU string `json:"cpu,omitempty"`
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
@@ -64,9 +63,6 @@ type TargetSpec struct {
OpenOCDCommands []string `json:"openocd-commands,omitempty"` OpenOCDCommands []string `json:"openocd-commands,omitempty"`
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device,omitempty"` 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"` CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"` RelocationModel string `json:"relocation-model,omitempty"`
WITPackage string `json:"wit-package,omitempty"` WITPackage string `json:"wit-package,omitempty"`
@@ -152,11 +148,6 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
// resolveInherits loads inherited targets, recursively. // resolveInherits loads inherited targets, recursively.
func (spec *TargetSpec) resolveInherits() error { 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. // First create a new spec with all the inherited properties.
newSpec := &TargetSpec{} newSpec := &TargetSpec{}
for _, name := range spec.Inherits { for _, name := range spec.Inherits {
@@ -182,9 +173,6 @@ func (spec *TargetSpec) resolveInherits() error {
} }
*spec = *newSpec *spec = *newSpec
// Restore InheritableOnly from the original spec, not from parents.
spec.InheritableOnly = inheritableOnly
return nil return nil
} }
@@ -251,17 +239,10 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
continue continue
} }
path := filepath.Join(dir, entry.Name()) path := filepath.Join(dir, entry.Name())
spec, err := LoadTarget(&Options{Target: path}) spec, err := LoadTarget(&Options{Target: path})
if err != nil { if err != nil {
return nil, fmt.Errorf("could not list target: %w", err) 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 == "" { if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like // This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json). // 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) { func TestOverrideProperties(t *testing.T) {
baseAutoStackSize := true baseAutoStackSize := true
base := &TargetSpec{ base := &TargetSpec{
+20 -109
View File
@@ -192,16 +192,6 @@ func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *bu
} }
} }
// 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 { type blockInfo struct {
// entry is the LLVM basic block corresponding to the start of this *ssa.Block. // entry is the LLVM basic block corresponding to the start of this *ssa.Block.
entry llvm.BasicBlock entry llvm.BasicBlock
@@ -324,6 +314,9 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Load comments such as //go:extern on globals. // Load comments such as //go:extern on globals.
c.loadASTComments(pkg) 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 { if c.NeedsStackObjects {
// Predeclare trackPointer, which is used everywhere we use runtime.alloc. // Predeclare trackPointer, which is used everywhere we use runtime.alloc.
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function)) c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
@@ -880,10 +873,6 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
// with a LLVM intrinsic. // with a LLVM intrinsic.
continue continue
} }
if ok := b.defineCryptoIntrinsic(); ok {
// Body of this function was replaced
continue
}
if member.Blocks == nil { if member.Blocks == nil {
// Try to define this as an intrinsic function. // Try to define this as an intrinsic function.
b.defineIntrinsicFunction() b.defineIntrinsicFunction()
@@ -1693,41 +1682,13 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
case "copy": case "copy":
dst := argValues[0] dst := argValues[0]
src := argValues[1] src := argValues[1]
// Fetch the lengths.
dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen") dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen")
srcLen := b.CreateExtractValue(src, 1, "copy.srcLen") srcLen := b.CreateExtractValue(src, 1, "copy.srcLen")
// Find the minimum of the lengths. dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
minFuncName := "llvm.umin.i" + strconv.Itoa(b.uintptrType.IntTypeWidth()) srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
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.
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem()) elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false) 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? return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
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
case "delete": case "delete":
m := argValues[0] m := argValues[0]
key := argValues[1] key := argValues[1]
@@ -1755,66 +1716,20 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
return llvmLen, nil return llvmLen, nil
case "min", "max": case "min", "max":
// min and max builtins, added in Go 1.21. // min and max builtins, added in Go 1.21.
// Find the corresponding intrinsic name. // We can simply reuse the existing binop comparison code, which has all
ty := argTypes[0].Underlying().(*types.Basic) // the edge cases figured out already.
llvmType := b.getLLVMType(ty) tok := token.LSS
info := ty.Info() if callName == "max" {
var prefix, delimeter, typeName string tok = token.GTR
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."
} }
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] result := argValues[0]
typ := argTypes[0]
for _, arg := range argValues[1:] { 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 return result, nil
case "panic": case "panic":
@@ -1987,14 +1902,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.emitSV64Call(instr.Args, getPos(instr)) return b.emitSV64Call(instr.Args, getPos(instr))
case strings.HasPrefix(name, "(device/riscv.CSR)."): case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr) 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" { if b.GOOS != "darwin" {
return b.createSyscall(instr) 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"): case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
return b.createRawSyscallNoError(instr) return b.createRawSyscallNoError(instr)
case name == "runtime.supportsRecover": case name == "runtime.supportsRecover":
@@ -2183,7 +2094,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
} }
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
layoutValue := b.createObjectLayout(typ, expr.Pos()) 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) align := b.targetData.ABITypeAlignment(typ)
buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))) buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
return buf, nil return buf, nil
@@ -2415,7 +2326,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
} }
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap") sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos()) 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))) slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
// Extend or truncate if necessary. This is safe as we've already done // 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", "", ""}, {"channel.go", "", ""},
{"gc.go", "", ""}, {"gc.go", "", ""},
{"zeromap.go", "", ""}, {"zeromap.go", "", ""},
{"generics.go", "", ""},
} }
if goMinor >= 20 { if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""}) tests = append(tests, testCase{"go1.20.go", "", ""})
+1 -1
View File
@@ -488,7 +488,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
size := b.targetData.TypeAllocSize(deferredCallType) size := b.targetData.TypeAllocSize(deferredCallType)
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
nilPtr := llvm.ConstNull(b.dataPtrType) 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 { if b.NeedsStackObjects {
b.trackPointer(alloca) b.trackPointer(alloca)
-3
View File
@@ -99,9 +99,6 @@ func typeHasPointers(t llvm.Type) bool {
} }
return false return false
case llvm.ArrayTypeKind: case llvm.ArrayTypeKind:
if t.ArrayLength() == 0 {
return false
}
if typeHasPointers(t.ElementType()) { if typeHasPointers(t.ElementType()) {
return true return true
} }
+36 -152
View File
@@ -10,7 +10,6 @@ import (
"fmt" "fmt"
"go/token" "go/token"
"go/types" "go/types"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -18,12 +17,6 @@ import (
"tinygo.org/x/go-llvm" "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. // Type kinds for basic types.
// They must match the constants for the Kind type in src/reflect/type.go. // They must match the constants for the Kind type in src/reflect/type.go.
var basicTypes = [...]uint8{ var basicTypes = [...]uint8{
@@ -190,16 +183,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
typeFieldTypes := []*types.Var{ typeFieldTypes := []*types.Var{
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]), 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) { switch typ := typ.(type) {
case *types.Basic: case *types.Basic:
typeFieldTypes = append(typeFieldTypes, 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, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "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))), types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
) )
case *types.Chan: 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, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), 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: case *types.Array:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), 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, "numFields", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))), 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: case *types.Interface:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "methods", methodSetType),
) )
// TODO: methods
case *types.Signature: case *types.Signature:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), 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() pkgname = pkg.Name()
} }
pkgPathPtr := c.pkgPathPtr(pkgpath) 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{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), namedNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying c.getTypeCode(typ.Underlying()), // underlying
pkgPathPtr, // pkgpath pointer pkgPathPtr, // pkgpath pointer
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
} }
if len(methods) > 0 { metabyte |= 1 << 5 // "named" flag
typeFields = append(typeFields, methodSetValue) // methods
}
typeFields = append(typeFields, c.ctx.ConstString(pkgname+"."+name+"\x00", false)) // name
metabyte |= 1 << 5 // "named" flag
case *types.Chan: case *types.Chan:
var dir reflectChanDir var dir reflectChanDir
switch typ.Dir() { switch typ.Dir() {
@@ -367,20 +323,10 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
c.getTypeCode(typ.Elem()), // elementType c.getTypeCode(typ.Elem()), // elementType
} }
case *types.Pointer: 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{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), ptrNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(typ.Elem()), c.getTypeCode(typ.Elem()),
} }
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Array: case *types.Array:
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods 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) llvmStructType := c.getLLVMType(typ)
size := c.targetData.TypeStoreSize(llvmStructType) 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{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), structNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
pkgPathPtr, pkgPathPtr,
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields 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)) typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Interface: case *types.Interface:
typeFields = []llvm.Value{ typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
c.getTypeCode(types.NewPointer(typ)), // TODO: methods
methodSetValue,
}
case *types.Signature: case *types.Signature:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
// TODO: params, return values, etc // 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. // This type assertion always succeeds, so we can just set commaOk to true.
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true) commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
} else { } else {
// Type assert on an interface type with methods. // Type assert on interface type with methods.
// Create a call to a declared-but-not-defined function that will // This is a call to an interface type assert function.
// be lowered by the interface lowering pass into a type-ID // The interface lowering pass will define this function by filling it
// comparison chain. // with a type switch over all concrete types that implement this
commaOk = b.createInterfaceTypeAssert(intf, actualTypeNum) // 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 { } else {
name, _ := getTypeCodeName(expr.AssertedType) name, _ := getTypeCodeName(expr.AssertedType)
@@ -843,58 +783,20 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
return strings.Join(methods, "; ") return strings.Join(methods, "; ")
} }
// getMethodSetValue creates the method set struct value for a list of methods. // getInterfaceImplementsFunc returns a declared function that works as a type
// The struct contains a length and a sorted array of method signature pointers. // switch. The interface lowering pass will define this function.
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value { func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
// Create a sorted list of method signature global names. s, _ := getTypeCodeName(assertedType.Underlying())
type methodRef struct { fnName := s + ".$typeassert"
name string llvmFn := c.mod.NamedFunction(fnName)
value llvm.Value 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 return llvmFn
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)
} }
// getInvokeFunction returns the thunk to call the given interface method. The // 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 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 // 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 // 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. // value, dereferences or unpacks it if necessary, and calls the real method.
+8 -30
View File
@@ -50,24 +50,19 @@ func (b *builder) defineIntrinsicFunction() {
// and will otherwise be lowered to regular libc memcpy/memmove calls. // and will otherwise be lowered to regular libc memcpy/memmove calls.
func (b *builder) createMemoryCopyImpl() { func (b *builder) createMemoryCopyImpl() {
b.createFunctionStart(true) b.createFunctionStart(true)
params := b.fn.Params[0:3] fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
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())
llvmFn := b.mod.NamedFunction(fnName) llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() { if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType, b.dataPtrType, b.uintptrType, b.ctx.Int1Type()}, false) 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) 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 // createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
@@ -208,23 +203,6 @@ func (b *builder) defineMathOp() {
b.CreateRet(result) 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. // Implement most math/bits functions.
// //
// This implements all the functions that operate on bits. It does not yet // This implements all the functions that operate on bits. It does not yet
+96 -94
View File
@@ -1,10 +1,10 @@
package compiler package compiler
import ( import (
"encoding/binary"
"fmt" "fmt"
"go/token" "go/token"
"go/types" "go/types"
"math/big"
"strings" "strings"
"github.com/tinygo-org/tinygo/compileopts" "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. // Packed data is bigger than a pointer, so allocate it on the heap.
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
align := b.targetData.ABITypeAlignment(packedType) 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, sizeValue,
llvm.ConstNull(b.dataPtrType), llvm.ConstNull(b.dataPtrType),
llvm.Undef(b.dataPtrType), // unused context parameter
}, "") }, "")
packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))) packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
if b.NeedsStackObjects { 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. // 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 { 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. // Use the element type for arrays. This works even for nested arrays.
for { for {
kind := t.TypeKind() kind := t.TypeKind()
@@ -252,29 +248,54 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
break 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) 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) pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
pointerBits := pointerSize * 8 pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
if bitmapLen < pointerBits { if objectSizeBytes < pointerSize {
rawMask := binary.LittleEndian.Uint64(bitmap[0:8]) // Too small to contain a pointer.
layout := rawMask*pointerBits + bitmapLen layout := (uint64(1) << 1) | 1
layout <<= 1 return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
layout |= 1 }
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. pointerBits := pointerSize * 8
layout &= 1<<pointerBits - 1 var sizeFieldBits uint64
if (layout>>1)/pointerBits == rawMask { switch pointerBits {
// No set bits were shifted off. case 16:
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType) 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 // 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 // Try first whether the global already exists. All objects with a
// particular name have the same type, so this is possible. // 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) global := c.mod.NamedGlobal(globalName)
if !global.IsNil() { if !global.IsNil() {
return global return global
} }
// Create the global initializer. // Create the global initializer.
bitmapByteValues := make([]llvm.Value, bitmapBytes) bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
i8 := c.ctx.Int8Type() bitmap.FillBytes(bitmapBytes)
for i, b := range bitmap { reverseBytes(bitmapBytes) // big-endian to little-endian
bitmapByteValues[i] = llvm.ConstInt(i8, uint64(b), false) 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{ initializer := c.ctx.ConstStruct([]llvm.Value{
llvm.ConstInt(c.uintptrType, bitmapLen, false), llvm.ConstInt(c.uintptrType, objectSizeWords, false),
llvm.ConstArray(i8, bitmapByteValues), llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
}, false) }, false)
// Create the actual global.
global = llvm.AddGlobal(c.mod, initializer.Type(), globalName) global = llvm.AddGlobal(c.mod, initializer.Type(), globalName)
global.SetInitializer(initializer) global.SetInitializer(initializer)
global.SetUnnamedAddr(true) global.SetUnnamedAddr(true)
@@ -307,7 +329,6 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
global.SetLinkage(llvm.LinkOnceODRLinkage) global.SetLinkage(llvm.LinkOnceODRLinkage)
if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 { if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 {
// AVR doesn't have alignment by default. // AVR doesn't have alignment by default.
// The lowest bit must be unset to distinguish this from an inline layout.
global.SetAlignment(2) global.SetAlignment(2)
} }
if c.Debug && pos != token.NoPos { if c.Debug && pos != token.NoPos {
@@ -339,71 +360,52 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
return global return global
} }
// buildPointerBitmap scans the given LLVM type for pointers and sets bits in a // getPointerBitmap 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. // bigint at the word offset that contains a pointer. This scan is recursive.
func (c *compilerContext) buildPointerBitmap( func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
dst []byte, alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
ptrAlign uint64, switch typ.TypeKind() {
pos token.Pos,
t llvm.Type,
offset uint64,
) {
switch t.TypeKind() {
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind: case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
// These types do not contain pointers. return big.NewInt(0)
case llvm.PointerTypeKind: case llvm.PointerTypeKind:
// Set the corresponding position in the bitmap. return big.NewInt(1)
dst[offset/8] |= 1 << (offset % 8)
case llvm.StructTypeKind: case llvm.StructTypeKind:
// Recurse over struct elements. ptrs := big.NewInt(0)
for i, et := range t.StructElementTypes() { for i, subtyp := range typ.StructElementTypes() {
eo := c.targetData.ElementOffset(t, i) subptrs := c.getPointerBitmap(subtyp, pos)
if eo%uint64(ptrAlign) != 0 { if subptrs.BitLen() == 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")
}
continue continue
} }
c.buildPointerBitmap( offset := c.targetData.ElementOffset(typ, i)
dst, if offset%uint64(alignment) != 0 {
ptrAlign, // This error will let the compilation fail, but by continuing
pos, // the error can still easily be shown.
et, c.addError(pos, "internal error: allocated struct contains unaligned pointer")
offset+(eo/ptrAlign), continue
)
}
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")
} }
return subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
ptrs.Or(ptrs, subptrs)
} }
elementSize /= ptrAlign return ptrs
for i := 0; i < len; i++ { case llvm.ArrayTypeKind:
c.buildPointerBitmap( subtyp := typ.ElementType()
dst, subptrs := c.getPointerBitmap(subtyp, pos)
ptrAlign, ptrs := big.NewInt(0)
pos, if subptrs.BitLen() == 0 {
et, return ptrs
offset+uint64(i)*elementSize,
)
} }
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: default:
// Should not happen. // Should not happen.
panic("unknown LLVM type") panic("unknown LLVM type")
+157 -444
View File
@@ -3,28 +3,42 @@ package compiler
// This file emits the correct map intrinsics for map operations. // This file emits the correct map intrinsics for map operations.
import ( import (
"fmt"
"go/token" "go/token"
"go/types" "go/types"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
const hashArrayUnrollLimit = 4
// createMakeMap creates a new map object (runtime.hashmap) by allocating and // createMakeMap creates a new map object (runtime.hashmap) by allocating and
// initializing an appropriately sized object. // initializing an appropriately sized object.
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) { func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
mapType := expr.Type().Underlying().(*types.Map) mapType := expr.Type().Underlying().(*types.Map)
keyType := mapType.Key().Underlying() keyType := mapType.Key().Underlying()
llvmValueType := b.getLLVMType(mapType.Elem().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) keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType) valueSize := b.targetData.TypeAllocSize(llvmValueType)
llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false) llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false) llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
sizeHint := llvm.ConstInt(b.uintptrType, 8, false) sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil { if expr.Reserve != nil {
sizeHint = b.getValue(expr.Reserve, getPos(expr)) sizeHint = b.getValue(expr.Reserve, getPos(expr))
var err error var err error
@@ -33,42 +47,10 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
return llvm.Value{}, err return llvm.Value{}, err
} }
} }
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
// 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,
}, "")
return hashmap, nil 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 // 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. // 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) { 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. // Do the lookup. How it is done depends on the key type.
var commaOkValue llvm.Value var commaOkValue llvm.Value
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key, mapValueAlloca, mapValueSize} params := []llvm.Value{m, key, mapValueAlloca, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "") commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type: either binary-comparable or with // key can be compared with runtime.memequal
// compiler-generated hash/equal. // Store the key in an alloca, in the entry block to avoid dynamic stack
// growth.
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, mapKeyAlloca) b.CreateStore(key, mapKeyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
// Fetch the value from the hashmap.
params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize} params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize}
fnName := "hashmapBinaryGet" commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericGet"
}
commaOkValue = b.createRuntimeCall(fnName, params, "")
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize) 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 // 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) { func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value") valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
b.CreateStore(value, valueAlloca) b.CreateStore(value, valueAlloca)
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key, valueAlloca} params := []llvm.Value{m, key, valueAlloca}
b.createRuntimeCall("hashmapStringSet", params, "") b.createRuntimeCall("hashmapStringSet", params, "")
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type. // key can be compared with runtime.memequal
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca) b.CreateStore(key, keyAlloca)
fnName := "hashmapBinarySet" b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericSet"
}
params := []llvm.Value{m, keyAlloca, valueAlloca} params := []llvm.Value{m, keyAlloca, valueAlloca}
b.createRuntimeCall(fnName, params, "") b.createRuntimeCall("hashmapBinarySet", params, "")
b.emitLifetimeEnd(keyAlloca, keySize) 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) 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 // createMapDelete deletes a key from a map by calling the appropriate runtime
// function. It is the implementation of the Go delete() builtin. // 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 { func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key} params := []llvm.Value{m, key}
b.createRuntimeCall("hashmapStringDelete", params, "") b.createRuntimeCall("hashmapStringDelete", params, "")
return nil return nil
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type.
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca) b.CreateStore(key, keyAlloca)
fnName := "hashmapBinaryDelete" b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericDelete"
}
params := []llvm.Value{m, keyAlloca} params := []llvm.Value{m, keyAlloca}
b.createRuntimeCall(fnName, params, "") b.createRuntimeCall("hashmapBinaryDelete", params, "")
b.emitLifetimeEnd(keyAlloca, keySize) b.emitLifetimeEnd(keyAlloca, keySize)
return nil 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) llvmKeyType := b.getLLVMType(keyType)
llvmValueType := b.getLLVMType(valueType) 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. // 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") mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next") 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, "") 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. // End the lifetimes of the allocas, because we're done with them.
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize) b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
b.emitLifetimeEnd(mapValueAlloca, mapValueSize) b.emitLifetimeEnd(mapValueAlloca, mapValueSize)
@@ -217,9 +250,20 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
func hashmapIsBinaryKey(keyType types.Type) bool { func hashmapIsBinaryKey(keyType types.Type) bool {
switch keyType := keyType.Underlying().(type) { switch keyType := keyType.Underlying().(type) {
case *types.Basic: case *types.Basic:
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 || keyType.Kind() == types.UnsafePointer // TODO: unsafe.Pointer is also a binary key, but to support that we
// need to fix an issue with interp first (see
// https://github.com/tinygo-org/tinygo/pull/4898).
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
case *types.Pointer: case *types.Pointer:
return true 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: case *types.Array:
return hashmapIsBinaryKey(keyType.Elem()) return hashmapIsBinaryKey(keyType.Elem())
default: default:
@@ -227,399 +271,68 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
} }
} }
// hashmapKeyHashSignature returns the Go type signature for hashmap key hash func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
// functions: func(key unsafe.Pointer, size, seed uintptr) uint32 // We know that hashmapIsBinaryKey is true, so we only have to handle those types that can show up there.
func hashmapKeyHashSignature() *types.Signature { // To zero all undefined bytes, we iterate over all the fields in the type. For each element, compute the
return types.NewSignatureType(nil, nil, nil, // offset of that element. If it's Basic type, there are no internal padding bytes. For compound types, we recurse to ensure
types.NewTuple( // we handle nested types. Next, we determine if there are any padding bytes before the next
types.NewVar(token.NoPos, nil, "key", types.Typ[types.UnsafePointer]), // element and zero those as well.
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,
)
}
// hashmapKeyEqualSignature returns the Go type signature for hashmap key equal zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
// 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,
)
}
// hashmapKeyFuncName returns a canonical name for a generated hash or equal switch llvmType.TypeKind() {
// function based on the key type's underlying structure. Named types are case llvm.IntegerTypeKind:
// replaced with their underlying types so that structurally identical key // no padding bytes
// types (e.g., struct{i1; str1} and struct{i2; str2} where both i1, i2 are return nil
// int and str1, str2 are string) share the same generated function. case llvm.PointerTypeKind:
func hashmapKeyFuncName(prefix string, keyType types.Type) string { // mo padding bytes
return prefix + "." + hashmapCanonicalTypeName(keyType) return nil
} case llvm.ArrayTypeKind:
llvmArrayType := llvmType
llvmElemType := llvmType.ElementType()
// hashmapCanonicalTypeName returns a string representation of the hash/equal for i := 0; i < llvmArrayType.ArrayLength(); i++ {
// operations needed for a type, stripping named types where the operation does idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
// not depend on the name. Pointer and channel names do not include the element elemPtr := b.CreateInBoundsGEP(llvmArrayType, ptr, []llvm.Value{zero, idx}, "")
// type because their hash/equal operations only use the pointer word.
func hashmapCanonicalTypeName(t types.Type) string { // zero any padding bytes in this element
switch t := t.Underlying().(type) { b.zeroUndefBytes(llvmElemType, elemPtr)
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"
} }
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 case llvm.StructTypeKind:
// of a key of the given type. The function is generated on first call and llvmStructType := llvmType
// cached in the module. numFields := llvmStructType.StructElementTypesCount()
func (b *builder) getOrGenerateKeyHashFunc(keyType types.Type) llvm.Value { llvmElementTypes := llvmStructType.StructElementTypes()
name := hashmapKeyFuncName("hashmapKeyHash", keyType)
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
return fn
}
// Create the LLVM function type: for i := 0; i < numFields; i++ {
// (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
}
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false) idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "") elemPtr := b.CreateInBoundsGEP(llvmStructType, ptr, []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)
loopEntry := b.GetInsertBlock() // zero any padding bytes in this field
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.body") llvmElemType := llvmElementTypes[i]
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.done") b.zeroUndefBytes(llvmElemType, elemPtr)
b.CreateBr(loopBody) // zero any padding bytes before the next field, if any
b.SetInsertPointAtEnd(loopBody) offset := b.targetData.ElementOffset(llvmStructType, i)
storeSize := b.targetData.TypeStoreSize(llvmElemType)
fieldEndOffset := offset + storeSize
phiI := b.CreatePHI(b.uintptrType, "i") var nextOffset uint64
phiHash := b.CreatePHI(b.ctx.Int32Type(), "hash.acc") if i < numFields-1 {
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
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()
} else { } 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) if fieldEndOffset != nextOffset {
// Real parts n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
xReal := b.CreateLoad(floatType, xPtr, "x.real") llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
yReal := b.CreateLoad(floatType, yPtr, "y.real") paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), elemPtr, []llvm.Value{llvmStoreSize}, "")
realEq := b.CreateFCmp(llvm.FloatOEQ, xReal, yReal, "eq.real") b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
// 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
} }
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
} }
+8 -31
View File
@@ -34,7 +34,6 @@ type functionInfo struct {
interrupt bool // go:interrupt interrupt bool // go:interrupt
nobounds bool // go:nobounds nobounds bool // go:nobounds
noescape bool // go:noescape noescape bool // go:noescape
noheap bool // go:noheap
variadic bool // go:variadic (CGo only) variadic bool // go:variadic (CGo only)
inline inlineType // go:inline inline inlineType // go:inline
} }
@@ -162,7 +161,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "machine.keepAliveNoEscape", "machine.unsafeNoEscape": case "machine.keepAliveNoEscape", "machine.unsafeNoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) 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 // 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. // returns values that are never null and never alias to an existing value.
for _, attrName := range []string{"noalias", "nonnull"} { for _, attrName := range []string{"noalias", "nonnull"} {
@@ -185,37 +184,18 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// be modified. // be modified.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(2, 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("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": case "runtime.stringFromBytes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.stringFromRunes": case "runtime.stringFromRunes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 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": case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a // This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer // portable way (see gc_stack_portable.go). Indicate to the optimizer
@@ -477,9 +457,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
if len(f.Blocks) == 0 { if len(f.Blocks) == 0 {
info.noescape = true info.noescape = true
} }
case "//go:noheap":
// Ensure this function does not allocate on the heap.
info.noheap = true
case "//go:variadic": case "//go:variadic":
// The //go:variadic pragma is emitted by the CGo preprocessing // The //go:variadic pragma is emitted by the CGo preprocessing
// pass for C variadic functions. This includes both explicit // pass for C variadic functions. This includes both explicit
@@ -569,7 +546,7 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
} }
for i := 0; i < typ.NumFields(); i++ { for i := 0; i < typ.NumFields(); i++ {
ftyp := typ.Field(i).Type() ftyp := typ.Field(i).Type()
if types.Unalias(ftyp).String() == "structs.HostLayout" { if ftyp.String() == "structs.HostLayout" {
hasHostLayout = true hasHostLayout = true
continue continue
} }
-124
View File
@@ -349,130 +349,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 // createRawSyscallNoError emits instructions for the Linux-specific
// syscall.rawSyscallNoError function. // syscall.rawSyscallNoError function.
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) { func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
+33 -29
View File
@@ -10,30 +10,33 @@ target triple = "wasm32-unknown-wasi"
@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4 @main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.b = hidden global [2 x ptr] 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%0 = add i32 %x, %y %0 = add i32 %x, %y
ret i32 %0 ret i32 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq i32 %x, %y %0 = icmp eq i32 %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -47,14 +50,14 @@ divbyzero.next: ; preds = %entry
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.divideByZeroPanic(ptr) #0 declare void @runtime.divideByZeroPanic(ptr) #1
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -64,12 +67,12 @@ divbyzero.next: ; preds = %entry
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -83,12 +86,12 @@ divbyzero.next: ; preds = %entry
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -98,66 +101,66 @@ divbyzero.next: ; preds = %entry
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp oeq float %x, %y %0 = fcmp oeq float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp une float %x, %y %0 = fcmp une float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp olt float %x, %y %0 = fcmp olt float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp ole float %x, %y %0 = fcmp ole float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp ogt float %x, %y %0 = fcmp ogt float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fcmp oge float %x, %y %0 = fcmp oge float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; 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: entry:
ret float %x.r ret float %x.r
} }
; Function Attrs: nounwind ; 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: entry:
ret float %x.i ret float %x.i
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fadd float %x.r, %y.r %0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i %1 = fadd float %x.i, %y.i
@@ -167,7 +170,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fsub float %x.r, %y.r %0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i %1 = fsub float %x.i, %y.i
@@ -177,7 +180,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%0 = fmul float %x.r, %y.r %0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i %1 = fmul float %x.i, %y.i
@@ -191,18 +194,19 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.foo(ptr %context) unnamed_addr #1 { define hidden void @main.foo(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef) call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret void ret void
} }
attributes #0 = { "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,+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 #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+25 -21
View File
@@ -6,73 +6,76 @@ target triple = "wasm32-unknown-wasi"
%runtime.channelOp = type { ptr, ptr, i32, ptr } %runtime.channelOp = type { ptr, ptr, i32, ptr }
%runtime.chanSelectState = type { ptr, 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
%chan.value = alloca i32, align 4 %chan.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
store i32 3, ptr %chan.value, align 4 store i32 3, ptr %chan.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 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 16, ptr nonnull %chan.op)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
ret void ret void
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #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) ; 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 ; 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: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
%chan.value = alloca i32, align 4 %chan.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 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 4, ptr nonnull %chan.value)
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void 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 ; 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: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) 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) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) 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) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #1 { define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #2 {
entry: entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8 %select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4 %select.send.value = alloca i32, align 4
@@ -85,7 +88,7 @@ entry:
store ptr %ch2, ptr %0, align 4 store ptr %ch2, ptr %0, align 4
%.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12 %.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12
store ptr null, ptr %.repack3, align 4 store ptr null, ptr %.repack3, align 4
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #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) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
%1 = extractvalue { i32, i1 } %select.result, 0 %1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0 %2 = icmp eq i32 %1, 0
@@ -102,9 +105,10 @@ select.body: ; preds = %select.next
br label %select.done br label %select.done
} }
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "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 #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind } attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
+23 -23
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.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface }
%runtime._interface = type { ptr, ptr } %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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 { define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
declare void @main.external(ptr) #1 declare void @main.external(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferSimple(ptr %context) unnamed_addr #0 { define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca = alloca { i32, ptr }, align 4 %defer.alloca = alloca { i32, ptr }, align 4
%deferPtr = alloca ptr, align 4 %deferPtr = alloca ptr, align 4
@@ -109,14 +112,14 @@ rundefers.end3: ; preds = %rundefers.loophead6
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn ; 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 ; 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: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
@@ -124,14 +127,14 @@ entry:
ret void 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 ; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #0 { define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca2 = alloca { i32, ptr }, align 4 %defer.alloca2 = alloca { i32, ptr }, align 4
%defer.alloca = alloca { i32, ptr }, align 4 %defer.alloca = alloca { i32, ptr }, align 4
@@ -250,7 +253,7 @@ rundefers.end7: ; preds = %rundefers.loophead1
} }
; Function Attrs: nounwind ; 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: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
@@ -259,7 +262,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #4 call void @runtime.printint32(i32 5, ptr undef) #4
@@ -268,7 +271,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #0 { define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #1 {
entry: entry:
%deferPtr = alloca ptr, align 4 %deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4 store ptr null, ptr %deferPtr, align 4
@@ -312,11 +315,8 @@ rundefers.end: ; preds = %rundefers.loophead
br label %recover br label %recover
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferLoop(ptr %context) unnamed_addr #0 { define hidden void @main.deferLoop(ptr %context) unnamed_addr #1 {
entry: entry:
%deferPtr = alloca ptr, align 4 %deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4 store ptr null, ptr %deferPtr, align 4
@@ -405,7 +405,7 @@ rundefers.end1: ; preds = %rundefers.loophead4
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #0 { define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca = alloca { i32, ptr, i32 }, align 4 %defer.alloca = alloca { i32, ptr, i32 }, align 4
%deferPtr = alloca ptr, align 4 %deferPtr = alloca ptr, align 4
@@ -505,9 +505,9 @@ rundefers.end4: ; preds = %rundefers.loophead7
br label %recover 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 #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 = { "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 = { nocallback nofree nosync nounwind willreturn } 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 = { 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 #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { nounwind } attributes #4 = { nounwind }
attributes #5 = { nounwind returns_twice } attributes #5 = { nounwind returns_twice }
+16 -12
View File
@@ -3,16 +3,19 @@ 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-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -24,25 +27,25 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 { define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
entry: entry:
ret float 0x41F0000000000000 ret float 0x41F0000000000000
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 { define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 -1 ret i32 -1
} }
; Function Attrs: nounwind ; 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: entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 } ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
} }
; Function Attrs: nounwind ; 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: entry:
%0 = uitofp i32 %v to float %0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
@@ -52,7 +55,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -65,7 +68,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02 %withinmax = fcmp ole float %v, 2.550000e+02
@@ -77,7 +80,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%abovemin = fcmp oge float %v, -1.280000e+02 %abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02 %belowmax = fcmp ole float %v, 1.270000e+02
@@ -90,5 +93,6 @@ entry:
ret i8 %0 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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "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" }
+15 -11
View File
@@ -3,44 +3,48 @@ 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-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp eq ptr %callback.funcptr, null %0 = icmp eq ptr %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.next: ; preds = %entry 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 ret void
fpcall.throw: ; preds = %entry fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(ptr undef) #2 call void @runtime.nilPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.nilPanic(ptr) #0 declare void @runtime.nilPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.bar(ptr %context) unnamed_addr #1 { define hidden void @main.bar(ptr %context) unnamed_addr #2 {
entry: entry:
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef) call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret void ret void
} }
attributes #0 = { "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,+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 #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
-8
View File
@@ -24,10 +24,6 @@ var (
x *byte x *byte
y [61]uintptr y [61]uintptr
} }
struct5 *struct {
x *byte
y [30]uintptr
}
slice1 []byte slice1 []byte
slice2 []*int slice2 []*int
@@ -62,10 +58,6 @@ func newStruct() {
x *byte x *byte
y [61]uintptr y [61]uintptr
}) })
struct5 = new(struct {
x *byte
y [30]uintptr
})
} }
func newFuncValue() *func() { func newFuncValue() *func() {
+18 -22
View File
@@ -16,25 +16,27 @@ target triple = "wasm32-unknown-wasi"
@main.struct2 = hidden global ptr null, align 4 @main.struct2 = hidden global ptr null, align 4
@main.struct3 = hidden global ptr null, align 4 @main.struct3 = hidden global ptr null, align 4
@main.struct4 = 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.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.slice2 = 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 @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-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-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-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:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4 @"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 { define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %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 ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.newArray(ptr %context) unnamed_addr #1 { define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %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 ; Function Attrs: nounwind
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 { define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -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 %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 call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new1, ptr @main.struct2, align 4 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 call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new2, ptr @main.struct3, align 4 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 call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new3, ptr @main.struct4, align 4 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 ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 { define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
@@ -103,7 +99,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 { define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -125,7 +121,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3 %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
@@ -139,7 +135,7 @@ entry:
ret %runtime._interface %1 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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "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 #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+160 -78
View File
@@ -1,78 +1,144 @@
; ModuleID = 'generics.go' ; ModuleID = 'generics.go'
source_filename = "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" target triple = "wasm32-unknown-wasi"
%"main.Point[float32]" = type { float, float }
%"main.Point[int]" = type { i32, i32 } %"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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 { define hidden void @main.main(i8* %context) unnamed_addr #1 {
entry: 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) %bi = alloca %"main.Point[int]", align 8
%1 = call %"main.Point[int]" @"main.Add[int]"(i32 0, i32 0, i32 0, i32 0, ptr undef) %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 ret void
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %complit = alloca %"main.Point[float32]", align 8
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b = alloca %"main.Point[float32]", align 8
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3 %a = alloca %"main.Point[float32]", align 8
store float %a.X, ptr %a, align 4 %a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4 store float 0.000000e+00, float* %a.repack, align 8
store float %a.Y, ptr %a.repack9, align 4 %a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 store float 0.000000e+00, float* %a.repack9, align 4
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3 %0 = bitcast %"main.Point[float32]"* %a to i8*
store float %b.X, ptr %b, align 4 call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4 %a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
store float %b.Y, ptr %b.repack11, align 4 store float %a.X, float* %a.repack10, align 8
call void @main.checkSize(i32 4, ptr undef) #3 %a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
call void @main.checkSize(i32 8, ptr undef) #3 store float %a.Y, float* %a.repack11, align 4
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3 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 br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry deref.next: ; preds = %entry
br i1 false, label %deref.throw1, label %deref.next2 br i1 false, label %deref.throw1, label %deref.next2
deref.next2: ; preds = %deref.next deref.next2: ; preds = %deref.next
%0 = load float, ptr %a, align 4 %4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
%1 = load float, ptr %b, align 4 %5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
%2 = fadd float %0, %1 %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 br i1 false, label %deref.throw3, label %deref.next4
deref.next4: ; preds = %deref.next2 deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw5, label %deref.next6 br i1 false, label %deref.throw5, label %deref.next6
deref.next6: ; preds = %deref.next4 deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4 %9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4 %10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
%5 = load float, ptr %4, align 4 %11 = load float, float* %10, align 4
%6 = load float, ptr %3, align 4 %12 = load float, float* %9, align 4
br i1 false, label %store.throw, label %store.next br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next6 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 br i1 false, label %store.throw7, label %store.next8
store.next8: ; preds = %store.next store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4 %13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
%8 = fadd float %5, %6 %14 = fadd float %11, %12
store float %8, ptr %7, align 4 store float %14, float* %13, align 4
%.unpack = load float, ptr %complit, align 4 %.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
%9 = insertvalue %"main.Point[float32]" poison, float %.unpack, 0 %.unpack = load float, float* %.elt, align 8
%10 = insertvalue %"main.Point[float32]" %9, float %8, 1 %15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
ret %"main.Point[float32]" %10 %16 = insertvalue %"main.Point[float32]" %15, float %14, 1
ret %"main.Point[float32]" %16
deref.throw: ; preds = %entry deref.throw: ; preds = %entry
unreachable unreachable
@@ -93,64 +159,81 @@ store.throw7: ; preds = %store.next
unreachable unreachable
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare void @main.checkSize(i32, i8*) #0
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
declare void @main.checkSize(i32, ptr) #0 declare void @runtime.nilPanic(i8*) #0
declare void @runtime.nilPanic(ptr) #0
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %complit = alloca %"main.Point[int]", align 8
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b = alloca %"main.Point[int]", align 8
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3 %a = alloca %"main.Point[int]", align 8
store i32 %a.X, ptr %a, align 4 %a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4 store i32 0, i32* %a.repack, align 8
store i32 %a.Y, ptr %a.repack9, align 4 %a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 store i32 0, i32* %a.repack9, align 4
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3 %0 = bitcast %"main.Point[int]"* %a to i8*
store i32 %b.X, ptr %b, align 4 call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4 %a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
store i32 %b.Y, ptr %b.repack11, align 4 store i32 %a.X, i32* %a.repack10, align 8
call void @main.checkSize(i32 4, ptr undef) #3 %a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
call void @main.checkSize(i32 8, ptr undef) #3 store i32 %a.Y, i32* %a.repack11, align 4
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3 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 br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry deref.next: ; preds = %entry
br i1 false, label %deref.throw1, label %deref.next2 br i1 false, label %deref.throw1, label %deref.next2
deref.next2: ; preds = %deref.next deref.next2: ; preds = %deref.next
%0 = load i32, ptr %a, align 4 %4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
%1 = load i32, ptr %b, align 4 %5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
%2 = add i32 %0, %1 %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 br i1 false, label %deref.throw3, label %deref.next4
deref.next4: ; preds = %deref.next2 deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw5, label %deref.next6 br i1 false, label %deref.throw5, label %deref.next6
deref.next6: ; preds = %deref.next4 deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4 %9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4 %10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
%5 = load i32, ptr %4, align 4 %11 = load i32, i32* %10, align 4
%6 = load i32, ptr %3, align 4 %12 = load i32, i32* %9, align 4
br i1 false, label %store.throw, label %store.next br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next6 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 br i1 false, label %store.throw7, label %store.next8
store.next8: ; preds = %store.next store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4 %13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
%8 = add i32 %5, %6 %14 = add i32 %11, %12
store i32 %8, ptr %7, align 4 store i32 %14, i32* %13, align 4
%.unpack = load i32, ptr %complit, align 4 %.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
%9 = insertvalue %"main.Point[int]" poison, i32 %.unpack, 0 %.unpack = load i32, i32* %.elt, align 8
%10 = insertvalue %"main.Point[int]" %9, i32 %8, 1 %15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
ret %"main.Point[int]" %10 %16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
ret %"main.Point[int]" %16
deref.throw: ; preds = %entry deref.throw: ; preds = %entry
unreachable unreachable
@@ -171,7 +254,6 @@ store.throw7: ; preds = %store.next
unreachable unreachable
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "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,+nontrapping-fptoint,+sign-ext" }
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 #2 = { nounwind }
attributes #3 = { nounwind }
+17 -13
View File
@@ -5,24 +5,27 @@ target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 } %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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 ret ptr %s.data
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp slt i16 %len, 0 %0 = icmp slt i16 %len, 0
@@ -36,24 +39,25 @@ unsafe.String.next: ; preds = %entry
%5 = zext nneg i16 %len to i32 %5 = zext nneg i16 %len to i32
%6 = insertvalue %runtime._string undef, ptr %ptr, 0 %6 = insertvalue %runtime._string undef, ptr %ptr, 0
%7 = insertvalue %runtime._string %6, i32 %5, 1 %7 = insertvalue %runtime._string %6, i32 %5, 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret %runtime._string %7 ret %runtime._string %7
unsafe.String.throw: ; preds = %entry unsafe.String.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #2 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.unsafeSlicePanic(ptr) #0 declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind ; 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 readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+57 -59
View File
@@ -5,32 +5,32 @@ target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 } %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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret i32 %a ret i32 %a
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smin.i32(i32, i32) #2
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -38,7 +38,7 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -47,109 +47,91 @@ entry:
} }
; Function Attrs: nounwind ; 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: entry:
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b) %0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
ret i8 %0 ret i8 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.umin.i8(i8, i8) #2
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #2
; Function Attrs: nounwind ; 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: entry:
%0 = call float @llvm.minimum.f32(float %a, float %b) %0 = fcmp olt float %a, %b
ret float %0 %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 ; 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: entry:
%0 = call double @llvm.minimum.f64(double %a, double %b) %0 = fcmp olt double %a, %b
ret double %0 %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 ; 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 readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1 %1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0 %2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1 %3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 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 %5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data %6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4 call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5 ret %runtime._string %5
} }
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #2
; Function Attrs: nounwind ; 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: entry:
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b) %0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #2
; Function Attrs: nounwind ; 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: entry:
%0 = call float @llvm.maximum.f32(float %a, float %b) %0 = fcmp ogt float %a, %b
ret float %0 %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 ; 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 readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1 %1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0 %2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1 %3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 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 %5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data %6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4 call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5 ret %runtime._string %5
} }
; Function Attrs: nounwind ; 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: entry:
%0 = shl i32 %s.len, 2 %0 = shl i32 %s.len, 2
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false) 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 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
; Function Attrs: nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
call void @runtime.hashmapClear(ptr %m, ptr undef) #4 call void @runtime.hashmapClear(ptr %m, ptr undef) #5
ret void 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" } ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } declare i32 @llvm.smin.i32(i32, i32) #4
attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; 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,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "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" }
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) } 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 }
+56 -63
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 @"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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 { define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), 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) #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) #9
ret void ret void
} }
declare void @main.regularFunction(i32, ptr) #1 declare void @main.regularFunction(i32, ptr) #2
; Function Attrs: nounwind ; 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: entry:
%unpack.int = ptrtoint ptr %0 to i32 %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 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 ; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), 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) #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) #9
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef) call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
@@ -56,28 +59,25 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: 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 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 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %n, ptr %1, align 4 store ptr %n, ptr %1, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #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) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
%2 = load i32, ptr %n, align 4 %2 = load i32, ptr %n, align 4
call void @runtime.printlock(ptr undef) #11 call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #11 call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #11 call void @runtime.printunlock(ptr undef) #9
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind ; 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: entry:
store i32 7, ptr %context, align 4 store i32 7, ptr %context, align 4
ret void ret void
@@ -93,23 +93,23 @@ entry:
ret void 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 ; 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: 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 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4 store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8 %2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store ptr %fn.funcptr, ptr %2, align 4 store ptr %fn.funcptr, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #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) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
ret void ret void
} }
@@ -121,43 +121,38 @@ entry:
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8 %4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4 %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 ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
ret void ret void
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
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
; Function Attrs: nounwind ; 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: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11 call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void ret void
} }
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1 declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #2
; Function Attrs: nounwind ; 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: 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 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
@@ -165,15 +160,15 @@ entry:
store i32 4, ptr %2, align 4 store i32 4, ptr %2, align 4
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12 %3 = getelementptr inbounds nuw i8, ptr %0, i32 12
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %3, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #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) #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) #9
ret void 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 ; 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: entry:
%1 = load ptr, ptr %0, align 4 %1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4 %2 = getelementptr inbounds nuw i8, ptr %0, i32 4
@@ -182,19 +177,17 @@ entry:
%5 = load i32, ptr %4, align 4 %5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12 %6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%7 = load ptr, ptr %6, align 4 %7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #11 call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
ret void ret void
} }
attributes #0 = { 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 #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 = { "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 = { 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 #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.inlineFunctionGoroutine$1" } 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 = { 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 #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 #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 #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 #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 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } 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 = { "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 #9 = { nounwind }
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 }
+63 -70
View File
@@ -5,85 +5,85 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1 @"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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: 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 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 ; 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: entry:
%unpack.int = ptrtoint ptr %0 to i32 %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
call void @runtime.deadlock(ptr undef) #11 call void @runtime.deadlock(ptr undef) #9
unreachable unreachable
} }
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0 declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: 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 ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef) 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 unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %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) #11 call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
store i32 3, ptr %n, align 4 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 %n, ptr nonnull %stackalloc, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #11 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) #11 %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) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %n, ptr %1, align 4 store ptr %n, ptr %1, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #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 %2 = load i32, ptr %n, align 4
call void @runtime.printlock(ptr undef) #11 call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #11 call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printunlock(ptr undef) #11 call void @runtime.printunlock(ptr undef) #9
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind ; 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: entry:
store i32 7, ptr %context, align 4 store i32 7, ptr %context, align 4
ret void ret void
@@ -96,28 +96,28 @@ entry:
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4 %2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3) call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
call void @runtime.deadlock(ptr undef) #11 call void @runtime.deadlock(ptr undef) #9
unreachable 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 ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%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
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4 store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8 %2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store ptr %fn.funcptr, ptr %2, align 4 store ptr %fn.funcptr, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void ret void
} }
@@ -129,46 +129,41 @@ entry:
%3 = load ptr, ptr %2, align 4 %3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8 %4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4 %5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #11 call void %5(i32 %1, ptr %3) #9
call void @runtime.deadlock(ptr undef) #11 call void @runtime.deadlock(ptr undef) #9
unreachable unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
ret void ret void
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
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
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11 call void @runtime.chanClose(ptr %ch, ptr undef) #9
ret void 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 ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%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
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store ptr %itf.value, ptr %0, align 4 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
@@ -176,14 +171,14 @@ entry:
store i32 4, ptr %2, align 4 store i32 4, ptr %2, align 4
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12 %3 = getelementptr inbounds nuw i8, ptr %0, i32 12
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %3, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #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 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 ; 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: entry:
%1 = load ptr, ptr %0, align 4 %1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4 %2 = getelementptr inbounds nuw i8, ptr %0, i32 4
@@ -192,20 +187,18 @@ entry:
%5 = load i32, ptr %4, align 4 %5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12 %6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%7 = load ptr, ptr %6, align 4 %7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #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) #11 call void @runtime.deadlock(ptr undef) #9
unreachable unreachable
} }
attributes #0 = { "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,+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 #1 = { "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 #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
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 #3 = { 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 #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 #4 = { 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 #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 #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 #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 #7 = { "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 #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } attributes #8 = { 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 #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 #9 = { nounwind }
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 }
+44 -42
View File
@@ -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: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:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4 @"reflect/types.type: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, [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: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.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1 @"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:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4 @"reflect/types.type: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 } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
@"reflect/types.typeid:basic:int" = external constant i8 @"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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null } ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null } ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null } ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 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) #6 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 } ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
} }
; Function Attrs: nounwind ; 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: 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 br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -76,12 +77,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next 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 ; 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: 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 br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -91,12 +92,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next 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 ; 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: 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 br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -106,33 +107,34 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next 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 ; 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: 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 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 ; 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: entry:
%stackalloc = alloca i8, align 1 %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 %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 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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "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 #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
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 #3 = { "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 #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 #4 = { "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 #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 #5 = { "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 #6 = { nounwind } attributes #6 = { "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 #7 = { nounwind }
+16 -12
View File
@@ -3,44 +3,48 @@ 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-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret [0 x i32] zeroinitializer ret [0 x i32] zeroinitializer
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 ret ptr %x
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 ret ptr %x
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 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 #0 = { 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 #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+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 //go:noescape
func stillEscapes(a *int, b []int, c chan int, d *[0]byte) { func stillEscapes(a *int, b []int, c chan int, d *[0]byte) {
} }
//go:noheap
func doesHeapAlloc() *int {
return new(int)
}
+30 -40
View File
@@ -11,105 +11,95 @@ target triple = "wasm32-unknown-wasi"
@undefinedGlobalNotInSection = external global i32, align 4 @undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024 @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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define void @extern_func() #2 { define void @extern_func() #3 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 { define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
declare void @somepkg.someFunction2(ptr) #0 declare void @somepkg.someFunction2(ptr) #1
; Function Attrs: inlinehint nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.useGeneric(ptr %context) unnamed_addr #1 { define hidden void @main.useGeneric(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"main.noinlineGenericFunc[int8]"(ptr undef) call void @"main.noinlineGenericFunc[int8]"(ptr undef)
ret void ret void
} }
; Function Attrs: noinline nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; 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: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define void @exportedFunctionInSection() #5 section ".special_function_section" { define void @exportedFunctionInSection() #6 section ".special_function_section" {
entry: entry:
ret void ret void
} }
declare void @main.declaredImport() #6 declare void @main.declaredImport() #7
declare void @imported() #7 declare void @imported() #8
; Function Attrs: nounwind ; Function Attrs: nounwind
define void @exported() #8 { define void @exported() #9 {
entry: entry:
ret void 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 ; 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: entry:
ret void ret void
} }
; Function Attrs: nounwind attributes #0 = { 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" }
define hidden ptr @main.doesHeapAlloc(ptr %context) unnamed_addr #1 { attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
entry: attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
%stackalloc = alloca i8, align 1 attributes #3 = { 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" }
%new = call align 4 dereferenceable(4) ptr @runtime.alloc_noheap(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #10 attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #10 attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
ret ptr %new attributes #6 = { 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 #7 = { "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 #8 = { "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" }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) attributes #9 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
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 }
+66 -74
View File
@@ -3,28 +3,31 @@ 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-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret i32 %ints.len ret i32 %ints.len
} }
; Function Attrs: nounwind ; 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: entry:
ret i32 %ints.cap ret i32 %ints.cap
} }
; Function Attrs: nounwind ; 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: entry:
%.not = icmp ult i32 %index, %ints.len %.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw br i1 %.not, label %lookup.next, label %lookup.throw
@@ -35,93 +38,84 @@ lookup.next: ; preds = %entry
ret i32 %1 ret i32 %1
lookup.throw: ; preds = %entry lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #5 call void @runtime.lookupPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.lookupPanic(ptr) #0 declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 %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) #5 call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
store i32 1, ptr %varargs, align 4 store i32 1, ptr %varargs, align 4
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4 %0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4
store i32 2, ptr %0, align 4 store i32 2, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8 %1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8
store i32 3, ptr %1, align 4 store i32 3, ptr %1, align 4
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr 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 nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0 %append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1 %append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2 %append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0 %2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1 %3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1
%4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2 %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 ret { ptr, i32, i32 } %4
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #1
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
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %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 nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0 %append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1 %append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2 %append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0 %0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1 %1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2 %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 ret { ptr, i32, i32 } %2
} }
; Function Attrs: nounwind ; 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: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
%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)
ret i32 %copy.n ret i32 %copy.n
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
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
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.next: ; preds = %entry 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 %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 %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 ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5 call void @runtime.slicePanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.slicePanic(ptr) #0 declare void @runtime.slicePanic(ptr) #1
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
@@ -129,20 +123,20 @@ entry:
slice.next: ; preds = %entry slice.next: ; preds = %entry
%makeslice.cap = shl nuw i32 %len, 1 %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 %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 %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 ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5 call void @runtime.slicePanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1431655765 %slice.maxcap = icmp ugt i32 %len, 1431655765
@@ -150,20 +144,20 @@ entry:
slice.next: ; preds = %entry slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3 %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 %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 %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 ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5 call void @runtime.slicePanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1073741823 %slice.maxcap = icmp ugt i32 %len, 1073741823
@@ -171,39 +165,39 @@ entry:
slice.next: ; preds = %entry slice.next: ; preds = %entry
%makeslice.cap = shl nuw i32 %len, 2 %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 %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 %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 ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #5 call void @runtime.slicePanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = getelementptr i8, ptr %p, i32 %len %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 ret ptr %0
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = trunc i64 %len to i32 %0 = trunc i64 %len to i32
%1 = getelementptr i8, ptr %p, i32 %0 %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 ret ptr %1
} }
; Function Attrs: nounwind ; 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: entry:
%0 = icmp ult i32 %s.len, 4 %0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
@@ -212,18 +206,18 @@ slicetoarray.next: ; preds = %entry
ret ptr %s.data ret ptr %s.data
slicetoarray.throw: ; preds = %entry slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(ptr undef) #5 call void @runtime.sliceToArrayPointerPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.sliceToArrayPointerPanic(ptr) #0 declare void @runtime.sliceToArrayPointerPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 { define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 %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) #5 call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
br i1 false, label %slicetoarray.throw, label %slicetoarray.next br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry slicetoarray.next: ; preds = %entry
@@ -234,7 +228,7 @@ slicetoarray.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i32 %len, 1073741823 %0 = icmp ugt i32 %len, 1073741823
@@ -248,18 +242,18 @@ unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1 %6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2 %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 ret { ptr, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.unsafeSlicePanic(ptr) #0 declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp eq ptr %ptr, null %0 = icmp eq ptr %ptr, null
@@ -272,16 +266,16 @@ unsafe.Slice.next: ; preds = %entry
%4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1 %5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2 %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 ret { ptr, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823 %0 = icmp ugt i64 %len, 1073741823
@@ -296,16 +290,16 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
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 ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; 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: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823 %0 = icmp ugt i64 %len, 1073741823
@@ -320,17 +314,15 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
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 ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #5 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
attributes #0 = { "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,+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 #1 = { "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 #2 = { 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 speculatable willreturn memory(none) } attributes #3 = { nounwind }
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind }
+25 -21
View File
@@ -7,34 +7,37 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1 @"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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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: entry:
ret %runtime._string { ptr @"main$string", i32 3 } ret %runtime._string { ptr @"main$string", i32 3 }
} }
; Function Attrs: nounwind ; 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: entry:
ret %runtime._string zeroinitializer ret %runtime._string zeroinitializer
} }
; Function Attrs: nounwind ; 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 readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 %s.len ret i32 %s.len
} }
; Function Attrs: nounwind ; 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 readonly %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
entry: entry:
%.not = icmp ult i32 %index, %s.len %.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw br i1 %.not, label %lookup.next, label %lookup.throw
@@ -45,40 +48,40 @@ lookup.next: ; preds = %entry
ret i8 %1 ret i8 %1
lookup.throw: ; preds = %entry lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2 call void @runtime.lookupPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.lookupPanic(ptr) #0 declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind ; 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 readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: 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 ret i1 %0
} }
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; 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 readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: 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 %1 = xor i1 %0, true
ret i1 %1 ret i1 %1
} }
; Function Attrs: nounwind ; 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 readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: 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 ret i1 %0
} }
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; 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 readonly %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = zext i8 %x to i32 %0 = zext i8 %x to i32
%.not = icmp ugt i32 %s.len, %0 %.not = icmp ugt i32 %s.len, %0
@@ -90,10 +93,11 @@ lookup.next: ; preds = %entry
ret i8 %2 ret i8 %2
lookup.throw: ; preds = %entry lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2 call void @runtime.lookupPanic(ptr undef) #3
unreachable unreachable
} }
attributes #0 = { "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,+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 #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+54 -24
View File
@@ -5,16 +5,19 @@ target triple = "wasm32-unknown-wasi"
%main.hasPadding = type { i1, i32, i1 } %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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; 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: entry:
%hashmap.key = alloca %main.hasPadding, align 8 %hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4 %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 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4 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 nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds nuw 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) 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) 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) ; 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) ; 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 ; 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: entry:
%hashmap.key = alloca %main.hasPadding, align 8 %hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -51,16 +60,20 @@ entry:
store i32 5, ptr %hashmap.value, align 4 store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4 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 nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds nuw 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 12, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void 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 ; 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: entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -71,15 +84,23 @@ entry:
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12 %hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4 %0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds nuw 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) 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) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %1 ret i32 %5
} }
; Function Attrs: noinline nounwind ; 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: entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -91,20 +112,29 @@ entry:
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12 %hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4 %0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds nuw 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 24, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 { define hidden void @main.main(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
attributes #0 = { "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,+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 #1 = { "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 #2 = { 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 #3 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { nounwind } 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-invaliddep"},
{name: "loader-invalidpackage"}, {name: "loader-invalidpackage"},
{name: "loader-nopackage"}, {name: "loader-nopackage"},
{name: "noheap", target: "cortex-m-qemu"},
{name: "optimizer"}, {name: "optimizer"},
{name: "syntax"}, {name: "syntax"},
{name: "types"}, {name: "types"},
Generated
+4 -4
View File
@@ -20,16 +20,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1770136044, "lastModified": 1747953325,
"narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=", "narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e", "rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "id": "nixpkgs",
"ref": "nixos-25.11", "ref": "nixos-25.05",
"type": "indirect" "type": "indirect"
} }
}, },
+1 -1
View File
@@ -34,7 +34,7 @@
inputs = { inputs = {
# Use a recent stable release, but fix the version to make it reproducible. # Use a recent stable release, but fix the version to make it reproducible.
# This version should be updated from time to time. # 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"; flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = { self, nixpkgs, flake-utils }: outputs = { self, nixpkgs, flake-utils }:
+5 -29
View File
@@ -1,53 +1,29 @@
module github.com/tinygo-org/tinygo module github.com/tinygo-org/tinygo
go 1.23.0 go 1.22.0
require ( require (
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/gofrs/flock v0.8.1 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/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-tty v0.0.4 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/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
github.com/tetratelabs/wazero v1.9.0 github.com/tetratelabs/wazero v1.6.0
go.bug.st/serial v1.6.4 go.bug.st/serial v1.6.0
go.bytecodealliance.org v0.6.2
go.bytecodealliance.org/cm v0.2.2
golang.org/x/net v0.35.0 golang.org/x/net v0.35.0
golang.org/x/sys v0.30.0 golang.org/x/sys v0.30.0
golang.org/x/tools v0.30.0 golang.org/x/tools v0.30.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/espflasher v0.6.0 tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6
) )
require ( 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/creack/goselect v0.1.2 // 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/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/stretchr/testify v1.8.4 // 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
golang.org/x/text v0.22.0 // indirect golang.org/x/text v0.22.0 // indirect
) )
+7 -69
View File
@@ -1,36 +1,17 @@
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 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw= 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 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/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/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 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 h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= 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 h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= 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/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw= 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/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -42,57 +23,18 @@ 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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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.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 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/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 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= 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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
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/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
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=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
@@ -102,7 +44,6 @@ 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-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-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-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-20220811171246-fbc7d0a398ab/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
@@ -115,10 +56,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/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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/go-llvm v0.0.0-20250422114502-b8f170971e74 h1:ovavgTdIBWCH8YWlcfq9gkpoyT1+IxMKSn+Df27QwE8=
tinygo.org/x/espflasher v0.6.0/go.mod h1:tr5u08HoE67WD5zxJesCiiVF/R1b6Akz3yXwh5zah8U= tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
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=
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const version = "0.42.0-dev" const version = "0.40.1"
// Return TinyGo version, either in the form 0.30.0 or as a development version // Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012). // (like 0.30.0-dev-abcd012).
+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. // Install tools specified in go.mod.
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom. // See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
package main package tools
import ( import (
_ "github.com/golangci/misspell" _ "github.com/golangci/misspell"
_ "github.com/mgechev/revive" _ "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/golangci/misspell/cmd/misspell
//go:generate go install github.com/mgechev/revive //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)") errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
errMapAlreadyCreated = errors.New("interp: map already created") errMapAlreadyCreated = errors.New("interp: map already created")
errLoopUnrolled = errors.New("interp: loop unrolled") 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 // 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 { func isRecoverableError(err error) bool {
return err == errIntegerAsPointer || err == errUnsupportedInst || return err == errIntegerAsPointer || err == errUnsupportedInst ||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated || err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
err == errLoopUnrolled || err == errLoopTooLong || err == errInvalidPtrToIntSize err == errLoopUnrolled
} }
// ErrorLine is one line in a traceback. The position may be missing. // 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. // runner contains all state related to one interp run.
type runner struct { type runner struct {
mod llvm.Module mod llvm.Module
targetData llvm.TargetData targetData llvm.TargetData
builder llvm.Builder builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData pointerSize uint32 // cached pointer size from the TargetData
dataPtrType llvm.Type // often used type so created in advance dataPtrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
byteOrder binary.ByteOrder // big-endian or little-endian byteOrder binary.ByteOrder // big-endian or little-endian
debug bool // log debug messages debug bool // log debug messages
pkgName string // package name of the currently executing package pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions functionCache map[llvm.Value]*function // cache of compiled functions
objects []object // slice of objects in memory objects []object // slice of objects in memory
globals map[llvm.Value]int // map from global to index in objects slice globals map[llvm.Value]int // map from global to index in objects slice
start time.Time start time.Time
timeout time.Duration timeout time.Duration
maxLoopIterations int callsExecuted uint64
callsExecuted uint64
interpErr error // set by Uint/Int when they encounter pointer data
} }
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{ r := runner{
mod: mod, mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()), targetData: llvm.NewTargetData(mod.DataLayout()),
byteOrder: llvmutil.ByteOrder(mod.Target()), byteOrder: llvmutil.ByteOrder(mod.Target()),
debug: debug, debug: debug,
functionCache: make(map[llvm.Value]*function), functionCache: make(map[llvm.Value]*function),
objects: []object{{}}, objects: []object{{}},
globals: make(map[llvm.Value]int), globals: make(map[llvm.Value]int),
start: time.Now(), start: time.Now(),
timeout: timeout, timeout: timeout,
maxLoopIterations: maxLoopIterations,
} }
r.pointerSize = uint32(r.targetData.PointerSize()) r.pointerSize = uint32(r.targetData.PointerSize())
r.dataPtrType = llvm.PointerType(mod.Context().Int8Type(), 0) 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. // Run evaluates runtime.initAll function as much as possible at compile time.
// Set debug to true if it should print output while running. // Set debug to true if it should print output while running.
func Run(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bool) error { func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
r := newRunner(mod, timeout, maxLoopIterations, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initAll := mod.NamedFunction("runtime.initAll") 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. // RunFunc evaluates a single package initializer at compile time.
// Set debug to true if it should print output while running. // 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. // Create and initialize *runner object.
mod := fn.GlobalParent() mod := fn.GlobalParent()
r := newRunner(mod, timeout, maxLoopIterations, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initName := fn.Name() initName := fn.Name()
if !strings.HasSuffix(initName, ".init") { if !strings.HasSuffix(initName, ".init") {
+12 -3
View File
@@ -2,6 +2,7 @@ package interp
import ( import (
"os" "os"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
@@ -10,17 +11,25 @@ import (
) )
func TestInterp(t *testing.T) { 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{ for _, name := range []string{
"basic", "basic",
"phi", "phi",
"slice-copy",
"consteval", "consteval",
"intrinsics",
"copy",
"interface", "interface",
"revert", "revert",
"alloc", "alloc",
} { } {
name := name // make local to this closure name := name // make local to this closure
if name == "slice-copy" && llvmVersion < 14 {
continue
}
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
t.Parallel() t.Parallel()
runTest(t, "testdata/"+name) runTest(t, "testdata/"+name)
@@ -44,7 +53,7 @@ func runTest(t *testing.T, pathPrefix string) {
defer mod.Dispose() defer mod.Dispose()
// Perform the transform. // Perform the transform.
err = Run(mod, 10*time.Minute, DefaultMaxInterpBlockEntries, false) err = Run(mod, 10*time.Minute, false)
if err != nil { if err != nil {
if err, match := err.(*Error); match { if err, match := err.(*Error); match {
println(err.Error()) println(err.Error())
+110 -53
View File
@@ -12,12 +12,6 @@ import (
"tinygo.org/x/go-llvm" "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) { func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent string) (value, memoryView, *Error) {
mem := memoryView{r: r, parent: parentMem} mem := memoryView{r: r, parent: parentMem}
locals := make([]value, len(fn.locals)) 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. // This is used to prevent unrolling.
var runtimeBlocks map[int]struct{} 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. // Start with the first basic block and the first instruction.
// Branch instructions may modify both bb and instIndex when branching. // Branch instructions may modify both bb and instIndex when branching.
bb := fn.blocks[0] 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++ { for instIndex := 0; instIndex < len(bb.instructions); instIndex++ {
if instIndex == 0 { if instIndex == 0 {
// This is the start of a new basic block. // 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 len(mem.instructions) != startRTInsts {
if _, ok := runtimeBlocks[lastBB]; ok { if _, ok := runtimeBlocks[lastBB]; ok {
// This loop has been unrolled. // 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 // means that monotonic time in the time package is counted from
// time.Time{}.Sub(1), which should be fine. // time.Time{}.Sub(1), which should be fine.
locals[inst.localIndex] = literalValue{uint64(0)} 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 // Allocate heap memory. At compile time, this is instead done
// by creating a global variable. // 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) fmt.Fprintln(os.Stderr, indent+"runtime.alloc:", size, "->", ptr)
} }
locals[inst.localIndex] = ptr locals[inst.localIndex] = ptr
case strings.HasPrefix(callFn.name, "llvm.umin."): case callFn.name == "runtime.sliceCopy":
locals[inst.localIndex] = makeLiteralInt(min(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth()) // sliceCopy implements the built-in copy function for slices.
case strings.HasPrefix(callFn.name, "llvm.smin."): // It is implemented here so that it can be used even if the
locals[inst.localIndex] = makeLiteralInt(uint64(min(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth()) // runtime implementation is not available. Doing it this way
case strings.HasPrefix(callFn.name, "llvm.umax."): // may also be faster.
locals[inst.localIndex] = makeLiteralInt(max(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth()) // Code:
case strings.HasPrefix(callFn.name, "llvm.smax."): // func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int {
locals[inst.localIndex] = makeLiteralInt(uint64(max(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth()) // n := srcLen
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"): // if n > dstLen {
// Copy a block of memory from one pointer to another. // n = dstLen
if operands[4].Uint(r) != 0 { // }
// This is a volatile copy/move. // memmove(dst, src, n*elemSize)
err := r.runAtRuntime(fn, inst, locals, &mem, indent) // return int(n)
if err != nil { // }
return nil, mem, err dstLen := operands[3].Uint(r)
} srcLen := operands[4].Uint(r)
continue elemSize := operands[5].Uint(r)
n := srcLen
if n > dstLen {
n = dstLen
} }
nBytes := operands[3].Uint(r) if r.debug {
if nBytes != 0 { 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. // 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 // (or both) are nil, the asPointer method call will fail
// even though copying a nil slice is allowed. // even though copying a nil slice is allowed.
dst, err := operands[1].asPointer(r) dst, err := operands[1].asPointer(r)
@@ -380,10 +363,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
continue continue
} }
nBytes := uint32(n * elemSize)
srcObj := mem.get(src.index()) srcObj := mem.get(src.index())
dstObj := mem.getWritable(dst.index()) dstObj := mem.getWritable(dst.index())
if srcObj.buffer == nil || dstObj.buffer == nil { 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 // This can happen for example when copying data out of
// a //go:embed slice, which is not available at interp // a //go:embed slice, which is not available at interp
// time. // time.
@@ -396,10 +380,33 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
dstBuf := dstObj.buffer.asRawValue(r) dstBuf := dstObj.buffer.asRawValue(r)
srcBuf := srcObj.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 dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj) 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": case callFn.name == "runtime.typeAssert":
// This function must be implemented manually as it is normally // This function must be implemented manually as it is normally
// implemented by the interface lowering pass. // 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. // Special function that will trigger an error.
// This is used to test error reporting. // This is used to test error reporting.
return nil, mem, r.errorAt(inst, errors.New("test error")) 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"): case strings.HasSuffix(callFn.name, "$invoke"):
// This thunk is the interface method dispatcher: it is called // This thunk is the interface method dispatcher: it is called
// with all regular parameters and a type code. It will then // with all regular parameters and a type code. It will then
@@ -847,14 +912,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
return nil, mem, r.errorAt(inst, errUnsupportedInst) 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")) 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 { func (v pointerValue) Uint(r *runner) uint64 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer to integer")
return 0
} }
func (v pointerValue) Int(r *runner) int64 { func (v pointerValue) Int(r *runner) int64 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer to integer")
return 0
} }
func (v pointerValue) equal(rhs pointerValue) bool { func (v pointerValue) equal(rhs pointerValue) bool {
@@ -738,12 +736,11 @@ func (v rawValue) asRawValue(r *runner) rawValue {
return v return v
} }
func (v rawValue) bytes(r *runner) []byte { func (v rawValue) bytes() []byte {
buf := make([]byte, len(v.buf)) buf := make([]byte, len(v.buf))
for i, p := range v.buf { for i, p := range v.buf {
if p > 255 { if p > 255 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer value to byte")
return buf
} }
buf[i] = byte(p) buf[i] = byte(p)
} }
@@ -751,10 +748,7 @@ func (v rawValue) bytes(r *runner) []byte {
} }
func (v rawValue) Uint(r *runner) uint64 { func (v rawValue) Uint(r *runner) uint64 {
buf := v.bytes(r) buf := v.bytes()
if r.interpErr != nil {
return 0
}
switch len(v.buf) { switch len(v.buf) {
case 1: case 1:
-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
}
-21
View File
@@ -245,7 +245,6 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"internal/cm/": false, "internal/cm/": false,
"internal/futex/": false, "internal/futex/": false,
"internal/fuzz/": false, "internal/fuzz/": false,
"internal/itoa/": false,
"internal/reflectlite/": false, "internal/reflectlite/": false,
"internal/gclayout": false, "internal/gclayout": false,
"internal/task/": false, "internal/task/": false,
@@ -268,31 +267,11 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths["crypto/internal/boring/sig/"] = false 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 { if needsSyscallPackage {
paths["syscall/"] = true // include syscall/js paths["syscall/"] = true // include syscall/js
paths["internal/syscall/"] = true paths["internal/syscall/"] = true
paths["internal/syscall/unix/"] = false 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 return paths
} }
+41 -78
View File
@@ -304,29 +304,6 @@ func (p *Program) Sorted() []*Package {
return p.sorted 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 // MainPkg returns the last package in the Sorted() slice. This is the main
// package of the program. // package of the program.
func (p *Program) MainPkg() *Package { func (p *Program) MainPkg() *Package {
@@ -572,7 +549,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
} }
// Look for //go:embed comments. // Look for //go:embed comments.
var allPatterns []embedPattern var allPatterns []string
for _, comment := range doc.List { for _, comment := range doc.List {
if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") { if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") {
continue continue
@@ -600,7 +577,21 @@ func (p *Package) extractEmbedLines(addError func(error)) {
}) })
continue 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 { if len(allPatterns) != 0 {
@@ -633,8 +624,8 @@ func (p *Package) extractEmbedLines(addError func(error)) {
// Match all //go:embed patterns against the embed files // Match all //go:embed patterns against the embed files
// provided by `go list`. // provided by `go list`.
for _, name := range p.EmbedFiles { for _, name := range p.EmbedFiles {
for _, ep := range allPatterns { for _, pattern := range allPatterns {
if ep.Match(name) { if matchPattern(pattern, name) {
p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{ p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{
Name: name, Name: name,
NeedsData: byteSlice, NeedsData: byteSlice,
@@ -650,37 +641,13 @@ func (p *Package) extractEmbedLines(addError func(error)) {
} }
} }
// embedPattern represents a valid //go:embed pattern. // matchPattern returns true if (and only if) the given pattern would match the
// See: https://pkg.go.dev/embed#hdr-Directives // filename. The pattern could also match a parent directory of name, in which
type embedPattern struct { // case hidden files do not match.
pattern string // glob pattern without "all:" prefix func matchPattern(pattern, name string) bool {
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
// Match this file. // Match this file.
if matched, _ := path.Match(pattern, name); matched { matched, _ := path.Match(pattern, name)
if matched {
return true return true
} }
@@ -694,20 +661,17 @@ func (ep embedPattern) Match(name string) bool {
dir = path.Clean(dir) dir = path.Clean(dir)
if matched, _ := path.Match(pattern, dir); matched { if matched, _ := path.Match(pattern, dir); matched {
// Pattern matches the directory. // Pattern matches the directory.
if !includeHidden { suffix := name[len(dir):]
suffix := name[len(dir):] if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") { // Pattern matches a hidden file.
// Pattern matches a hidden file. // Hidden files are included when listed directly as a
// Hidden files are included when listed directly as a // pattern, but not when they are part of a directory tree.
// pattern, or when the "all:" prefix is used, but not // Source:
// when they are part of a directory tree without "all:". // > If a pattern names a directory, all files in the
// Source: // > subtree rooted at that directory are embedded
// > If a pattern names a directory, all files in the // > (recursively), except that files with names beginning
// > subtree rooted at that directory are embedded // > with . or _ are excluded.
// > (recursively), except that files with names beginning return false
// > with . or _ are excluded.
return false
}
} }
return true 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 // parseGoEmbed is like strings.Fields but for a //go:embed line. It parses
// regular fields and quoted fields (that may contain spaces). // 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) args = strings.TrimSpace(args)
initialLen := len(args) initialLen := len(args)
for args != "" { for args != "" {
patternPos := pos + token.Pos(initialLen-len(args)) patternPos := pos + token.Pos(initialLen-len(args))
var pattern string
switch args[0] { switch args[0] {
case '`', '"', '\\': case '`', '"', '\\':
// Parse the next pattern using the Go scanner. // 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", 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) args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace)
default: default:
// The value is just a regular value. // 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 { if index < 0 {
index = len(args) index = len(args)
} }
pattern = args[:index] pattern := args[:index]
patterns = append(patterns, pattern)
args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace) args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace)
} }
ep, err := newEmbedPattern(pattern) if _, err := path.Match(patterns[len(patterns)-1], ""); err != nil {
if err != nil {
return nil, types.Error{ return nil, types.Error{
Fset: p.program.fset, Fset: p.program.fset,
Pos: patternPos, Pos: patternPos,
Msg: "invalid pattern syntax", Msg: "invalid pattern syntax",
} }
} }
patterns = append(patterns, ep)
} }
return patterns, nil return patterns, nil
} }
+37 -171
View File
@@ -30,18 +30,14 @@ import (
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics" "github.com/tinygo-org/tinygo/diagnostics"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/interp"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/buildutil" "golang.org/x/tools/go/buildutil"
"tinygo.org/x/espflasher/pkg/espflasher"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
"go.bug.st/serial" "go.bug.st/serial"
"go.bug.st/serial/enumerator" "go.bug.st/serial/enumerator"
) )
var errInheritableOnly = errors.New("target is inheritable-only, which means it cannot be used directly for building or flashing")
// commandError is an error type to wrap os/exec.Command errors. This provides // commandError is an error type to wrap os/exec.Command errors. This provides
// some more information regarding what went wrong while running a command. // some more information regarding what went wrong while running a command.
type commandError struct { type commandError struct {
@@ -143,10 +139,6 @@ func printCommand(cmd string, args ...string) {
// Build compiles and links the given package and writes it to outpath. // Build compiles and links the given package and writes it to outpath.
func Build(pkgName, outpath string, config *compileopts.Config) error { func Build(pkgName, outpath string, config *compileopts.Config) error {
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
// Create a temporary directory for intermediary files. // Create a temporary directory for intermediary files.
tmpdir, err := os.MkdirTemp("", "tinygo") tmpdir, err := os.MkdirTemp("", "tinygo")
if err != nil { if err != nil {
@@ -364,10 +356,6 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
return err return err
} }
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
// determine the type of file to compile // determine the type of file to compile
var fileExt string var fileExt string
@@ -397,10 +385,6 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
fileExt = ".hex" fileExt = ".hex"
case "bmp": case "bmp":
fileExt = ".elf" fileExt = ".elf"
case "adb":
fileExt = ".hex"
case "esp32flash", "esp32jtag":
fileExt = ".bin"
case "native": case "native":
return errors.New("unknown flash method \"native\" - did you miss a -target flag?") return errors.New("unknown flash method \"native\" - did you miss a -target flag?")
default: default:
@@ -535,61 +519,11 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
case "adb":
// Run pre-flash adb shell commands.
for _, preCmd := range config.Target.ADBPreCommands {
cmd := executeCommand(config.Options, "adb", "shell", preCmd)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"failed to run adb pre-command", preCmd, err}
}
}
// Push the binary to the device.
if config.Target.ADBPushRemote == "" {
return errors.New("invalid target file: flash-method was set to \"adb\" but no adb-push-remote was set")
}
cmd := executeCommand(config.Options, "adb", "push", result.Binary, config.Target.ADBPushRemote)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"adb push failed to " + config.Target.ADBPushRemote, result.Binary, err}
}
// Run post-flash adb shell commands.
for _, postCmd := range config.Target.ADBPostCommands {
postCmd = strings.ReplaceAll(postCmd, "{remote}", config.Target.ADBPushRemote)
cmd := executeCommand(config.Options, "adb", "shell", postCmd)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"failed to run adb post-command", postCmd, err}
}
}
case "esp32flash":
port, err := getDefaultPort(port, config.Target.SerialPort)
if err != nil {
return &commandError{"failed to find port", port, err}
}
if err := flashBinUsingEsp32(port, classicReset, result.Binary, config.Options); err != nil {
return &commandError{"failed to flash", result.Binary, err}
}
case "esp32jtag":
port, err := getDefaultPort(port, config.Target.SerialPort)
if err != nil {
return &commandError{"failed to find port", port, err}
}
if err := flashBinUsingEsp32(port, jtagReset, result.Binary, config.Options); err != nil {
return &commandError{"failed to flash", result.Binary, err}
}
default: default:
return fmt.Errorf("unknown flash method: %s", flashMethod) return fmt.Errorf("unknown flash method: %s", flashMethod)
} }
if options.Monitor { if options.Monitor {
return Monitor(result.Executable, port, config) return Monitor(result.Executable, "", config)
} }
return nil return nil
} }
@@ -831,10 +765,6 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
return err return err
} }
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
_, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error { _, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run() return cmd.Run()
}) })
@@ -1089,68 +1019,6 @@ func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Opt
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]") return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
} }
const (
defaultReset = "default"
classicReset = "classic"
jtagReset = "jtag"
)
func flashBinUsingEsp32(port, resetMode, tmppath string, options *compileopts.Options) error {
opts := espflasher.DefaultOptions()
opts.Compress = true
opts.Logger = &espflasher.StdoutLogger{W: os.Stdout}
if options.BaudRate != 0 {
opts.FlashBaudRate = options.BaudRate
}
if resetMode == jtagReset {
opts.ResetMode = espflasher.ResetUSBJTAG
}
flasher, err := espflasher.New(port, opts)
if err != nil {
return err
}
defer flasher.Close()
chipName := flasher.ChipName()
offset := uint32(0x0)
if chipName == "ESP32" {
offset = 0x1000
}
// Read the firmware binary
data, err := os.ReadFile(tmppath)
if err != nil {
return err
}
if err := flasher.EraseFlash(); err != nil {
return fmt.Errorf("erase failed: %v", err)
}
progress := func(current, total int) {
pct := float64(current) / float64(total) * 100
bar := int(pct / 2)
fmt.Printf("\r[%-50s] %6.1f%%", strings.Repeat("#", bar)+strings.Repeat(".", 50-bar), pct)
if current >= total {
fmt.Println()
}
}
// Flash with progress reporting
err = flasher.FlashImage(data, offset, progress)
if err != nil {
return err
}
fmt.Println()
// Reset the device to run the new firmware
flasher.Reset()
return nil
}
type mountPoint struct { type mountPoint struct {
name string name string
path string path string
@@ -1739,7 +1607,6 @@ func main() {
serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)") serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)")
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit") work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout") interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
interpLoopLimit := flag.Int("interp-loop-limit", interp.DefaultMaxInterpBlockEntries, "maximum loop iterations during interp (0 to disable)")
var tags buildutil.TagsFlag var tags buildutil.TagsFlag
flag.Var(&tags, "tags", "a space-separated list of extra build tags") flag.Var(&tags, "tags", "a space-separated list of extra build tags")
target := flag.String("target", "", "chip/board name or JSON target specification file") target := flag.String("target", "", "chip/board name or JSON target specification file")
@@ -1857,43 +1724,42 @@ func main() {
} }
options := &compileopts.Options{ options := &compileopts.Options{
GOOS: goenv.Get("GOOS"), GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
GOMIPS: goenv.Get("GOMIPS"), GOMIPS: goenv.Get("GOMIPS"),
Target: *target, Target: *target,
BuildMode: *buildMode, BuildMode: *buildMode,
StackSize: stackSize, StackSize: stackSize,
Opt: *opt, Opt: *opt,
GC: *gc, GC: *gc,
PanicStrategy: *panicStrategy, PanicStrategy: *panicStrategy,
Scheduler: *scheduler, Scheduler: *scheduler,
Serial: *serial, Serial: *serial,
Work: *work, Work: *work,
InterpTimeout: *interpTimeout, InterpTimeout: *interpTimeout,
InterpMaxLoopIterations: *interpLoopLimit, PrintIR: *printIR,
PrintIR: *printIR, DumpSSA: *dumpSSA,
DumpSSA: *dumpSSA, VerifyIR: *verifyIR,
VerifyIR: *verifyIR, SkipDWARF: *skipDwarf,
SkipDWARF: *skipDwarf, Semaphore: make(chan struct{}, *parallelism),
Semaphore: make(chan struct{}, *parallelism), Debug: !*nodebug,
Debug: !*nodebug, Nobounds: *nobounds,
Nobounds: *nobounds, PrintSizes: *printSize,
PrintSizes: *printSize, PrintStacks: *printStacks,
PrintStacks: *printStacks, PrintAllocs: printAllocs,
PrintAllocs: printAllocs, Tags: []string(tags),
Tags: []string(tags), TestConfig: testConfig,
TestConfig: testConfig, GlobalValues: globalVarValues,
GlobalValues: globalVarValues, Programmer: *programmer,
Programmer: *programmer, OpenOCDCommands: ocdCommands,
OpenOCDCommands: ocdCommands, LLVMFeatures: *llvmFeatures,
LLVMFeatures: *llvmFeatures, Monitor: *monitor,
Monitor: *monitor, BaudRate: *baudrate,
BaudRate: *baudrate, Timeout: *timeout,
Timeout: *timeout, WITPackage: witPackage,
WITPackage: witPackage, WITWorld: witWorld,
WITWorld: witWorld, GoCompatibility: *gocompatibility,
GoCompatibility: *gocompatibility,
} }
if *printCommands { if *printCommands {
options.PrintCommands = printCommand options.PrintCommands = printCommand
+1 -24
View File
@@ -77,7 +77,6 @@ func TestBuild(t *testing.T) {
"interface.go", "interface.go",
"json.go", "json.go",
"map.go", "map.go",
"map_bigkey.go",
"math.go", "math.go",
"oldgo/", "oldgo/",
"print.go", "print.go",
@@ -108,9 +107,6 @@ func TestBuild(t *testing.T) {
if minor >= 23 { if minor >= 23 {
tests = append(tests, "go1.23/") tests = append(tests, "go1.23/")
} }
if minor >= 24 {
tests = append(tests, "typealias.go")
}
if *testTarget != "" { if *testTarget != "" {
// This makes it possible to run one specific test (instead of all), // This makes it possible to run one specific test (instead of all),
@@ -156,19 +152,6 @@ func TestBuild(t *testing.T) {
} }
runTestWithConfig("ldflags.go", t, opts, nil, nil) runTestWithConfig("ldflags.go", t, opts, nil, nil)
}) })
// Same as ldflags, but the global has a default value in source.
// -ldflags -X must override it, matching standard Go behaviour.
t.Run("ldflags-initialized", func(t *testing.T) {
t.Parallel()
opts := optionsFromTarget("", sema)
opts.GlobalValues = map[string]map[string]string{
"main": {
"someGlobal": "foobar",
},
}
runTestWithConfig("ldflags-initialized.go", t, opts, nil, nil)
})
}) })
if testing.Short() { if testing.Short() {
@@ -239,7 +222,6 @@ func TestBuild(t *testing.T) {
// to be sure. // to be sure.
t.Parallel() t.Parallel()
options := optionsFromOSARCH("linux/mipsle/softfloat", sema) options := optionsFromOSARCH("linux/mipsle/softfloat", sema)
emuCheck(t, options)
runTest("cgo/", options, t, nil, nil) runTest("cgo/", options, t, nil, nil)
}) })
} else if runtime.GOOS == "windows" { } else if runtime.GOOS == "windows" {
@@ -297,11 +279,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// limited amount of memory. // limited amount of memory.
continue continue
case "map_bigkey.go":
// Compiler generates many large stack temporaries for [256]byte
// map keys, overflowing the goroutine stack (384 bytes).
continue
case "gc.go": case "gc.go":
// Does not pass due to high mark false positive rate. // Does not pass due to high mark false positive rate.
continue continue
@@ -473,7 +450,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
// Build the test binary. // Build the test binary.
stdout := &bytes.Buffer{} stdout := &bytes.Buffer{}
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, 2*time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error { _, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run() return cmd.Run()
}) })
if err != nil { if err != nil {
@@ -1,56 +0,0 @@
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Stripped-down version of the entropy package for TinyGo.
//
// The upstream Go 1.26 package allocates a [1<<25]byte (32 MiB) global buffer
// for CPU jitter-based SP 800-90B entropy collection. This is fine on systems
// with virtual memory where BSS pages are lazily backed, but it causes a fatal
// "RAM overflowed" error on microcontrollers and other memory-constrained
// targets.
//
// Because FIPS 140-3 jitter entropy is never used on TinyGo targets (the DRBG
// falls through to sysrand.Read when fips140.Enabled is false), this overlay
// replaces the 32 MiB buffer with a zero-size type.
package entropy
// Version returns the version of the entropy source.
func Version() string {
return "v1.0.0"
}
// ScratchBuffer is a large buffer in upstream Go (32 MiB). TinyGo replaces it
// with a zero-size type since the CPU jitter entropy source is not used.
type ScratchBuffer [0]byte
// Seed returns a 384-bit seed with full entropy.
// On TinyGo targets this is never called because FIPS mode is not enabled.
func Seed(memory *ScratchBuffer) ([48]byte, error) {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// Samples collects entropy samples. Not supported on TinyGo targets.
func Samples(samples []uint8, memory *ScratchBuffer) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// SHA384 computes SHA-384 over 1024 bytes. Not supported on TinyGo targets.
func SHA384(p *[1024]byte) [48]byte {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// TestingOnlySHA384 computes SHA-384 over arbitrary bytes. Not supported on TinyGo targets.
func TestingOnlySHA384(p []byte) [48]byte {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// RepetitionCountTest implements the repetition count test from SP 800-90B.
func RepetitionCountTest(samples []uint8) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// AdaptiveProportionTest implements the adaptive proportion test from SP 800-90B.
func AdaptiveProportionTest(samples []uint8) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) //go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt)
// If you update the above build constraint, you'll probably also need to update // If you update the above build constraint, you'll probably also need to update
// src/runtime/rand_hwrng.go. // src/runtime/rand_hwrng.go.
-397
View File
@@ -1,397 +0,0 @@
// Startup code for the ESP32-S3 (Xtensa LX7, windowed ABI).
//
// The ROM bootloader loads IRAM/DRAM segments into SRAM but does NOT
// configure flash cache/MMU. We must:
// 1. Set up the windowed-ABI register file and stack pointer.
// 2. Set VECBASE and clear PS.EXCM (needed for callx4 window overflows).
// 3. Disable watchdog timers.
// 4. Configure the flash cache and MMU so IROM/DROM are accessible.
// 5. Jump to runtime.main (in IROM).
//
// Cache/MMU init sequence (from NuttX esp_loader.c / ESP-IDF bootloader / esp-hal):
// Phase A configure cache modes:
// a. rom_config_instruction_cache_mode(16KB, 8-way, 32B)
// b. rom_Cache_Suspend_DCache()
// c. rom_config_data_cache_mode(32KB, 8-way, 32B)
// d. Cache_Resume_DCache(0)
// Phase B map flash pages:
// e. Disable caches
// f. Cache_MMU_Init() reset all MMU entries to invalid
// g. Cache_Set_IDROM_MMU_Size() set IROM/DROM entry split
// h. Write MMU entries mapping flash page 0 for IROM and DROM
// i. Clear bus-shut bits
// j. Enable caches + isync
#define PS_WOE 0x00040000
// -----------------------------------------------------------------------
// Boot entry point placed in IRAM by the linker.
// -----------------------------------------------------------------------
.section .text.call_start_cpu0
.literal_position
.align 4
.Lstack_top_addr:
.long _stack_top
.Lmain_addr:
.long main
.Lvector_table_addr:
.long _vector_table
// WDT register addresses
.Lwdt_key:
.long 0x50D83AA1
.Lrtc_wdt_protect:
.long 0x600080B0
.Lrtc_wdt_config0:
.long 0x60008098
.Ltimg0_wdt_protect:
.long 0x6001F064
.Ltimg0_wdt_config0:
.long 0x6001F048
.Ltimg1_wdt_protect:
.long 0x60020064
.Ltimg1_wdt_config0:
.long 0x60020048
.Lswd_protect:
.long 0x600080B8
.Lswd_key:
.long 0x8F1D312A
.Lswd_conf:
.long 0x600080B4
.Lswd_disable:
.long 0x40000000
// ROM function addresses (from ESP-IDF esp32s3.rom.ld)
.Lrom_config_icache:
.long 0x40001a1c
.Lrom_config_dcache:
.long 0x40001a28
.Lrom_suspend_dcache:
.long 0x400018b4
.LCache_Resume_DCache:
.long 0x400018c0
.LCache_Disable_ICache:
.long 0x4000186c
.LCache_Disable_DCache:
.long 0x40001884
.LCache_MMU_Init:
.long 0x40001998
.LCache_Set_IDROM_MMU_Size:
.long 0x40001914
.LCache_Enable_ICache:
.long 0x40001878
.LCache_Enable_DCache:
.long 0x40001890
// Cache/MMU register addresses
.Lmmu_table_base:
.long 0x600C5000
.Licache_ctrl1_reg:
.long 0x600C4064
.Ldcache_ctrl1_reg:
.long 0x600C4004
// End-of-section symbols for multi-page MMU mapping.
.Lirom_end:
.long _irom_end
.Ldrom_end:
.long _drom_end
.Lirom_base:
.long 0x42000000
.Ldrom_base:
.long 0x3C000000
.global call_start_cpu0
call_start_cpu0:
// ---- 1. Windowed-ABI register file setup ----
// Disable WOE so we can safely manipulate WINDOWSTART.
rsr.ps a2
movi a3, ~(PS_WOE)
and a2, a2, a3
wsr.ps a2
rsync
// Set WINDOWSTART to 1 << WINDOWBASE (mark only current window as valid).
rsr.windowbase a2
ssl a2
movi a2, 1
sll a2, a2
wsr.windowstart a2
rsync
// Load stack pointer.
l32r a1, .Lstack_top_addr
// Re-enable WOE.
rsr.ps a2
movi a3, PS_WOE
or a2, a2, a3
wsr.ps a2
rsync
// Enable FPU (coprocessor 0).
movi a2, 1
wsr.cpenable a2
rsync
// ---- 2. Disable all watchdog timers (IMMEDIATELY, before any delay) ----
l32r a3, .Lwdt_key
movi a4, 0
// RTC WDT
l32r a2, .Lrtc_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Lrtc_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// TIMG0 WDT
l32r a2, .Ltimg0_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Ltimg0_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// TIMG1 WDT
l32r a2, .Ltimg1_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Ltimg1_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// Super WDT
l32r a2, .Lswd_protect
l32r a3, .Lswd_key
memw
s32i a3, a2, 0
l32r a5, .Lswd_conf
l32r a6, .Lswd_disable
memw
s32i a6, a5, 0
memw
s32i a4, a2, 0
// ---- 3. Set VECBASE and clear PS.EXCM ----
// VECBASE must be set before any callx4 so that window overflow
// exceptions (triggered by register window rotation) route to our
// handlers in IRAM, not the ROM's default vectors.
l32r a8, .Lvector_table_addr
wsr.vecbase a8
rsync
// Clear PS.EXCM (bit 4) and PS.INTLEVEL (bits 0-3).
// The ROM bootloader may leave EXCM=1; with EXCM set any callx4
// window overflow would become a double exception.
// Set PS.UM (bit 5) so level-1 exceptions route to User vector.
rsr.ps a2
movi a3, ~0x1F
and a2, a2, a3
movi a3, 0x20
or a2, a2, a3
wsr.ps a2
rsync
// ---- 4. Configure flash cache and MMU ----
//
// ROM function calls use callx4 (windowed ABI):
// a4 = target address (overwritten with return addr by call mechanism)
// a5 = stack pointer for callee (becomes callee's a1 via entry)
// a6 = first argument (becomes callee's a2)
// a7 = second argument (becomes callee's a3)
// a8 = third argument (becomes callee's a4)
// Registers a0-a3 are preserved across callx4; a4-a11 may be clobbered.
// Phase A: Configure cache modes (required for cache hardware to function).
// Without this, the cache doesn't know its size/associativity/line-size
// and cannot service flash accesses.
// 4a. Configure ICache mode: 16KB, 8-way, 32-byte line
movi a6, 0x4000 // cache_size = 16KB
movi a7, 8 // ways = 8
movi a8, 32 // line_size = 32
mov a5, a1
l32r a4, .Lrom_config_icache
callx4 a4
// 4b. Suspend DCache before configuring it
mov a5, a1
l32r a4, .Lrom_suspend_dcache
callx4 a4
// 4c. Configure DCache mode: 32KB, 8-way, 32-byte line
movi a6, 0x8000 // cache_size = 32KB
movi a7, 8 // ways = 8
movi a8, 32 // line_size = 32
mov a5, a1
l32r a4, .Lrom_config_dcache
callx4 a4
// 4d. Resume DCache
movi a6, 0
mov a5, a1
l32r a4, .LCache_Resume_DCache
callx4 a4
// Phase B: Map flash pages into MMU.
// 4e. Disable ICache
mov a5, a1
l32r a4, .LCache_Disable_ICache
callx4 a4
// 4f. Disable DCache
mov a5, a1
l32r a4, .LCache_Disable_DCache
callx4 a4
// 4g. Initialize MMU (resets all 512 entries to invalid = 0x4000)
mov a5, a1
l32r a4, .LCache_MMU_Init
callx4 a4
// 4h. Set IDROM MMU size: even 256/256 split.
// Each entry is 4 bytes, so 256 entries = 0x400 bytes per region.
movi a6, 0x400 // irom_mmu_size (256 entries × 4 bytes)
movi a7, 0x400 // drom_mmu_size (256 entries × 4 bytes)
mov a5, a1
l32r a4, .LCache_Set_IDROM_MMU_Size
callx4 a4
// 4i. Map flash pages for IROM and DROM using identity mapping.
// MMU table at 0x600C5000: entries 0-255 = ICache, 256-511 = DCache.
// Entry value N = flash page N (SOC_MMU_VALID = 0 on S3).
// Each 64KB page needs one 4-byte entry.
//
// IROM: map pages 0..N where N = (_irom_end - 0x42000000) >> 16
// DROM: map pages 0..M where M = (_drom_end - 0x3C000000) >> 16
l32r a8, .Lmmu_table_base // a8 = 0x600C5000
// --- IROM pages ---
l32r a2, .Lirom_end // a2 = _irom_end (VMA in 0x42xxxxxx)
l32r a3, .Lirom_base // a3 = 0x42000000
sub a2, a2, a3 // a2 = byte offset past IROM base
srli a2, a2, 16 // a2 = last page index
addi a2, a2, 1 // a2 = number of pages to map
movi a9, 0 // a9 = page counter (and entry value)
mov a10, a8 // a10 = current MMU entry pointer
.Lirom_loop:
s32i a9, a10, 0
addi a9, a9, 1
addi a10, a10, 4
blt a9, a2, .Lirom_loop
// --- DROM pages ---
l32r a2, .Ldrom_end // a2 = _drom_end (VMA in 0x3Cxxxxxx)
l32r a3, .Ldrom_base // a3 = 0x3C000000
sub a2, a2, a3 // a2 = byte offset past DROM base
srli a2, a2, 16 // a2 = last page index
addi a2, a2, 1 // a2 = number of pages to map
movi a9, 0 // a9 = page counter (and entry value)
addmi a10, a8, 0x400 // a10 = 0x600C5400 (DCache entry 256)
.Ldrom_loop:
s32i a9, a10, 0
addi a9, a9, 1
addi a10, a10, 4
blt a9, a2, .Ldrom_loop
memw
// 4j. Clear bus-shut bits so core 0 can access ICache and DCache buses.
l32r a8, .Licache_ctrl1_reg // 0x600C4064
movi a9, 0
s32i a9, a8, 0 // Clear all ICACHE_CTRL1 shut bits
l32r a8, .Ldcache_ctrl1_reg // 0x600C4004
s32i a9, a8, 0 // Clear all DCACHE_CTRL1 shut bits
memw
// 4k. Enable ICache (arg: autoload = 0)
movi a6, 0
mov a5, a1
l32r a4, .LCache_Enable_ICache
callx4 a4
// 4l. Enable DCache (arg: autoload = 0)
movi a6, 0
mov a5, a1
l32r a4, .LCache_Enable_DCache
callx4 a4
// Flush instruction pipeline so new cache/MMU config takes effect.
isync
// ---- 5. Jump to main (in IROM) ----
// Re-clear PS.EXCM in case ROM calls changed processor state.
rsr.ps a2
movi a3, ~0x1F
and a2, a2, a3
movi a3, 0x20
or a2, a2, a3
wsr.ps a2
rsync
mov a5, a1
l32r a4, .Lmain_addr
callx4 a4
// If main returns, loop forever.
1: j 1b
// -----------------------------------------------------------------------
// tinygo_scanCurrentStack Spill all Xtensa register windows to the
// stack, then call tinygo_scanstack(sp) so the conservative GC can
// discover live heap pointers that are currently in physical registers.
//
// On RISC-V / ARM the equivalent function pushes callee-saved registers
// before the call. On Xtensa windowed ABI the same effect is achieved
// by forcing hardware window-overflow for every occupied pane: each
// overflow saves the four registers in that pane to the stack frame
// pointed to by the pane's a1 (sp). After all panes are flushed, a
// scan from the current sp to stackTop covers every live value.
// -----------------------------------------------------------------------
.section .text.tinygo_scanCurrentStack
.global tinygo_scanCurrentStack
tinygo_scanCurrentStack:
entry a1, 48
// Disable interrupts while flushing register windows.
rsr a4, PS
s32i a4, a1, 0 // save PS for later restore
rsil a4, 3 // XCHAL_EXCM_LEVEL
// Flush all register windows using recursive call4.
// For NAREG=64 (16 panes), 15 recursive levels cover all panes
// except the current one (which is kept active).
movi a6, 15
call4 .Lscan_spill
// Restore interrupts.
l32i a4, a1, 0
wsr.ps a4
rsync
// Pass current sp to tinygo_scanstack.
// call4 maps caller's a5callee's a1 (stack ptr for callee's entry)
// and caller's a6callee's a2 (first argument = sp).
mov a5, a1 // callee's a1 = valid stack pointer
mov a6, a1 // callee's a2 = sp argument
call4 tinygo_scanstack
retw
.balign 4
.Lscan_spill:
entry a1, 16
beqz a2, .Lscan_spill_done
addi a2, a2, -1
mov a6, a2
call4 .Lscan_spill
.Lscan_spill_done:
retw
-11
View File
@@ -75,10 +75,6 @@ handleInterruptASM:
SFREG f30,(30 + 16)*REGSIZE(sp) SFREG f30,(30 + 16)*REGSIZE(sp)
SFREG f31,(31 + 16)*REGSIZE(sp) SFREG f31,(31 + 16)*REGSIZE(sp)
#endif #endif
// Save ra to a global so handleException can print the caller of the NULL
// function pointer.
la t0, tinygo_saved_ra
SREG ra, 0(t0)
call handleInterrupt call handleInterrupt
#ifdef __riscv_flen #ifdef __riscv_flen
LFREG f0, (31 + 16)*REGSIZE(sp) LFREG f0, (31 + 16)*REGSIZE(sp)
@@ -132,10 +128,3 @@ handleInterruptASM:
LREG ra, 0*REGSIZE(sp) LREG ra, 0*REGSIZE(sp)
addi sp, sp, NREG*REGSIZE addi sp, sp, NREG*REGSIZE
mret mret
.section .bss.tinygo_saved_ra
.global tinygo_saved_ra
.type tinygo_saved_ra,@object
.align 2
tinygo_saved_ra:
.space REGSIZE
+12 -2
View File
@@ -5,15 +5,25 @@ import (
"time" "time"
) )
// This example assumes that an analog sensor such as a rotary dial is connected to pin ADC0.
// When the dial is turned past the midway point, the built-in LED will light up.
func main() { func main() {
machine.InitADC() machine.InitADC()
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sensor := machine.ADC{machine.ADC2} sensor := machine.ADC{machine.ADC2}
sensor.Configure(machine.ADCConfig{}) sensor.Configure(machine.ADCConfig{})
for { for {
val := sensor.Get() val := sensor.Get()
println(val) if val < 0x8000 {
time.Sleep(time.Millisecond * 500) led.Low()
} else {
led.High()
}
time.Sleep(time.Millisecond * 100)
} }
} }
@@ -1,4 +1,4 @@
//go:build arduino_uno //go:build arduino
package main package main
-11
View File
@@ -1,11 +0,0 @@
//go:build xiao_esp32s3
package main
import "machine"
const (
button = machine.D1
buttonMode = machine.PinInputPullup
buttonPinChange = machine.PinFalling
)
-11
View File
@@ -1,11 +0,0 @@
//go:build arduino_uno_q
package main
import "machine"
var (
pwm = &machine.TIM3
pinA = machine.D3 // PB0 = TIM3_CH3
pinB = machine.D6 // PB1 = TIM3_CH4
)
@@ -1,4 +1,4 @@
//go:build arduino_uno //go:build arduino
package main package main
-12
View File
@@ -1,12 +0,0 @@
//go:build digispark
package main
import "machine"
var (
// Use Timer1 for PWM (recommended for ATtiny85)
pwm = machine.Timer1
pinA = machine.P1 // PB1, Timer1 channel A (LED pin)
pinB = machine.P4 // PB4, Timer1 channel B
)
-11
View File
@@ -1,11 +0,0 @@
//go:build esp32c3_supermini
package main
import "machine"
var (
pwm = machine.PWM0
pinA = machine.GPIO5
pinB = machine.GPIO6
)
-11
View File
@@ -1,11 +0,0 @@
//go:build pico2 || pico_plus2
package main
import "machine"
var (
pwm = machine.PWM0 // Pin 25 (LED on pico2) corresponds to PWM0.
//pinA = machine.LED
pinA = machine.GPIO16
)

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