mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-06 20:13:40 +00:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc959c5aab | |||
| ef77ed3103 | |||
| ca2694c5d9 | |||
| fd1d10c9b7 | |||
| 5c37d1ba61 | |||
| 610dd19c40 | |||
| 44ca224056 | |||
| c1cddffbe9 | |||
| 9bbad6700b | |||
| 24f965425d | |||
| b6b723aeec | |||
| 934d5f41bf | |||
| 4b0e858964 | |||
| 32378537b8 | |||
| f5b2a08b15 | |||
| f23e18a8de | |||
| 66d7099c96 | |||
| bef0dc5d21 | |||
| e79cdc1122 | |||
| f0256cab18 | |||
| 5d8e071bfb | |||
| a0069b6282 | |||
| 707d37a4c1 | |||
| 1876b65b18 | |||
| 1fe934e8a8 | |||
| 8bd2233b57 | |||
| ff58c50118 | |||
| ca36fba7e4 | |||
| 743bf45e00 | |||
| 9bc5d21185 | |||
| c8b56bd161 | |||
| fe20079300 | |||
| 068d7c1b44 | |||
| 42fed60e61 | |||
| 53c1ccaa42 | |||
| 72f667cac9 | |||
| 4fff472808 | |||
| cfd74c2954 | |||
| 9bcca974ba | |||
| a40586d092 | |||
| bc9708f51a | |||
| 8ef36ed939 | |||
| c7f62bae9b | |||
| 1b741bf2b7 | |||
| 266d70816f | |||
| 27cedf09e8 | |||
| db9f1182f5 | |||
| f7fd5cf2d8 | |||
| 8d9c9a16e3 | |||
| 82deccac40 | |||
| 0e540dc3da | |||
| 897f2bc5fd | |||
| 750b0e5c18 | |||
| a65ac105cc | |||
| 6970c80d34 | |||
| dfbc42f833 | |||
| e356daa229 | |||
| 1c27ecb66f | |||
| d01d0bb358 | |||
| 8fcf3658b1 | |||
| b37535bcfb | |||
| ee0a10ec51 | |||
| 39e0333663 | |||
| 3afd2c3597 | |||
| bd19f3baa3 | |||
| 908fa84d49 | |||
| 571f34e0e6 | |||
| 01723025d7 | |||
| 505b5ee565 | |||
| 26ac03a3f6 | |||
| c9aa88b8ef | |||
| 887ac286ff | |||
| b1083d78c7 | |||
| 7863bdb484 | |||
| 5c3363bf25 | |||
| 9404bb8712 | |||
| 20e22d4507 | |||
| 9118e91b72 | |||
| fbbaa5e580 | |||
| 97a2cb4a37 | |||
| 6dee98c3a1 | |||
| 484ccf830a | |||
| 5690204224 | |||
| b203314c2f | |||
| 5ae8fd1f6f | |||
| c80da7eb0d | |||
| 326ca4202e | |||
| 852dde671e | |||
| bf613175e7 | |||
| 4d62cca267 | |||
| a63aa143bb | |||
| ed0fb774b9 | |||
| 9be956f4bc | |||
| 48d741f68a | |||
| 35e6b8a67d | |||
| 8a31ae14a0 | |||
| 26ee3fb93e | |||
| 8872d5ebfc | |||
| faf455283d | |||
| 562b4c5020 | |||
| 7460734522 | |||
| 3be7100e89 | |||
| aedaf7d925 | |||
| 256e84f912 | |||
| 0a87846bd8 | |||
| 073862ee92 | |||
| c820d83ae2 | |||
| 109e0767e7 | |||
| 821f2aeae0 | |||
| 93a11e266f | |||
| e29e583919 | |||
| 310df7acb5 | |||
| b9387febe0 | |||
| 3dce224183 | |||
| 5d8afa25b8 | |||
| 0dca016749 | |||
| 28a911bcce | |||
| eb36120c6e | |||
| dfbb133ea6 | |||
| 79ab77facd | |||
| 2c99692019 | |||
| 0ca0aad7ce | |||
| 3ddba4e620 | |||
| eab3dceb48 | |||
| 663a94fcab | |||
| 373ca88f14 | |||
| be33de1086 | |||
| e5bdfb0962 | |||
| e80c6c48a1 | |||
| 381644a0c0 | |||
| 13bb59c334 | |||
| 632e5f9872 | |||
| 37531930b8 | |||
| 3869f76887 | |||
| 3e76703ff5 | |||
| deb48dd5f0 | |||
| 73fa5cd7bc | |||
| 1be7582106 | |||
| d5b7cdbca3 | |||
| c769262398 | |||
| 64caab1ade | |||
| 78914382c3 | |||
| 15e37ff927 | |||
| 91234060be | |||
| b33b6ce293 | |||
| 8911abbc6d | |||
| bc77922d47 | |||
| 34efc3a381 | |||
| 5c46efb4d1 | |||
| d6343d9d5c | |||
| e368551919 | |||
| 8b4624a420 | |||
| 9fd1b7b1a8 | |||
| a38829c692 | |||
| 1dbc6c83c4 | |||
| 9a6071920f | |||
| 0964176b4d | |||
| 1ffa9a4adf | |||
| 8c5886060f | |||
| 3bb092d4d4 | |||
| 20e62dea6f | |||
| 1b5d312c68 | |||
| 435ddc5f2d | |||
| 1de1f87c6b | |||
| 778164c98e | |||
| b3da00ac1f | |||
| e454ad1b61 | |||
| f845b469b1 | |||
| 35adbffa54 | |||
| 01f3d3eb59 | |||
| 0e43146d32 | |||
| 93f40992c1 | |||
| c6b47fe6a0 | |||
| 536deaa00a | |||
| df1d639deb |
+10
-8
@@ -92,16 +92,20 @@ commands:
|
|||||||
- /go/pkg/mod
|
- /go/pkg/mod
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-llvm15-go122:
|
test-oldest:
|
||||||
|
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||||
|
# least the smoke tests still pass.
|
||||||
docker:
|
docker:
|
||||||
- image: golang:1.22-bullseye
|
- image: golang:1.22-bullseye
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "15"
|
llvm: "15"
|
||||||
resource_class: large
|
resource_class: large
|
||||||
test-llvm20-go124:
|
test-newest:
|
||||||
|
# This tests the latest supported LLVM version when linking against system
|
||||||
|
# libraries.
|
||||||
docker:
|
docker:
|
||||||
- image: golang:1.24-bullseye
|
- image: golang:1.25-bullseye
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "20"
|
llvm: "20"
|
||||||
@@ -110,8 +114,6 @@ jobs:
|
|||||||
workflows:
|
workflows:
|
||||||
test-all:
|
test-all:
|
||||||
jobs:
|
jobs:
|
||||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
- test-oldest
|
||||||
# least the smoke tests still pass.
|
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
|
||||||
- test-llvm15-go122
|
# - test-newest
|
||||||
# This tests LLVM 20 support when linking against system libraries.
|
|
||||||
- test-llvm20-go124
|
|
||||||
|
|||||||
@@ -16,36 +16,37 @@ jobs:
|
|||||||
name: build-macos
|
name: build-macos
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# macos-13: amd64 (oldest supported version as of 18-10-2024)
|
# macos-14: arm64 (oldest supported version as of 18-11-2025)
|
||||||
# macos-14: arm64 (oldest arm64 version)
|
# macos-15-intel: amd64 (last intel version to be supported by github runners)
|
||||||
os: [macos-13, macos-14]
|
# See https://github.com/actions/runner-images/issues/13046
|
||||||
|
os: [macos-14, macos-15-intel]
|
||||||
include:
|
include:
|
||||||
- os: macos-13
|
|
||||||
goarch: amd64
|
|
||||||
- os: macos-14
|
- os: macos-14
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
|
- os: macos-15-intel
|
||||||
|
goarch: amd64
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
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@v4
|
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: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-${{ matrix.os }}-v1
|
key: llvm-source-20-${{ matrix.os }}-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -70,7 +71,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-19-${{ matrix.os }}-v1
|
key: llvm-build-20-${{ matrix.os }}-v2
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -79,7 +80,7 @@ jobs:
|
|||||||
rm -rf llvm-project
|
rm -rf llvm-project
|
||||||
make llvm-source
|
make llvm-source
|
||||||
# install dependencies
|
# install dependencies
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
|
HOMEBREW_NO_AUTO_UPDATE=1 brew install ninja
|
||||||
# build!
|
# build!
|
||||||
make llvm-build
|
make llvm-build
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
@@ -130,11 +131,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
brew install llvm@${{ matrix.version }}
|
brew install llvm@${{ matrix.version }}
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
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 }}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ 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@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
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@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
@@ -66,45 +66,3 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
- name: Trigger Drivers repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger Bluetooth repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger TinyFS repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger TinyFont repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger TinyDraw repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger TinyTerm repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
|
|||||||
+18
-18
@@ -18,7 +18,7 @@ jobs:
|
|||||||
# statically linked binary.
|
# statically linked binary.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: golang:1.24-alpine
|
image: golang:1.25-alpine
|
||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.version.outputs.version }}
|
version: ${{ steps.version.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
@@ -26,12 +26,12 @@ jobs:
|
|||||||
# tar: needed for actions/cache@v4
|
# 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
|
run: apk add tar git openssh make g++ ruby-dev mold
|
||||||
- name: Work around CVE-2022-24765
|
- name: Work around CVE-2022-24765
|
||||||
# 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@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Extract TinyGo version
|
- name: Extract TinyGo version
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-linux-alpine-v1
|
key: llvm-source-20-linux-alpine-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-19-linux-alpine-v1
|
key: llvm-build-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'
|
||||||
@@ -131,13 +131,13 @@ jobs:
|
|||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||||
@@ -164,7 +164,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
@@ -179,9 +179,9 @@ jobs:
|
|||||||
simavr \
|
simavr \
|
||||||
ninja-build
|
ninja-build
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
@@ -197,7 +197,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-linux-asserts-v1
|
key: llvm-source-20-linux-asserts-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -222,7 +222,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-19-linux-asserts-v1
|
key: llvm-build-20-linux-asserts-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'
|
||||||
@@ -284,7 +284,7 @@ jobs:
|
|||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
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"
|
||||||
@@ -296,15 +296,15 @@ jobs:
|
|||||||
g++-${{ matrix.toolchain }} \
|
g++-${{ matrix.toolchain }} \
|
||||||
libc6-dev-${{ matrix.libc }}-cross
|
libc6-dev-${{ matrix.libc }}-cross
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-linux-v1
|
key: llvm-source-20-linux-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -329,7 +329,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-19-linux-${{ matrix.goarch }}-v3
|
key: llvm-build-20-linux-${{ matrix.goarch }}-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'
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@@ -35,8 +35,8 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
tinygo/llvm-19
|
tinygo/llvm-20
|
||||||
ghcr.io/${{ github.repository_owner }}/llvm-19
|
ghcr.io/${{ github.repository_owner }}/llvm-20
|
||||||
tags: |
|
tags: |
|
||||||
type=sha,format=long
|
type=sha,format=long
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
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@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
target: tinygo-llvm-build
|
target: tinygo-llvm-build
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ 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@v4
|
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
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-linux-nix-v1
|
key: llvm-source-20-linux-nix-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/compiler-rt
|
llvm-project/compiler-rt
|
||||||
- name: Download LLVM source
|
- name: Download LLVM source
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
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@v22
|
- uses: cachix/install-nix-action@v31
|
||||||
- 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"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
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
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-sizediff-v1
|
key: llvm-source-20-sizediff-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/compiler-rt
|
llvm-project/compiler-rt
|
||||||
- name: Download LLVM source
|
- name: Download LLVM source
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install ninja binaryen
|
scoop install ninja binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Extract TinyGo version
|
- name: Extract TinyGo version
|
||||||
@@ -39,15 +39,15 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore cached LLVM source
|
- name: Restore cached LLVM source
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-19-windows-v1
|
key: llvm-source-20-windows-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-19-windows-v1
|
key: llvm-build-20-windows-v2
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -143,11 +143,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install binaryen
|
scoop install binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -173,11 +173,11 @@ jobs:
|
|||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
disk-root: "C:"
|
disk-root: "C:"
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -209,11 +209,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install binaryen && scoop install wasmtime@29.0.1
|
scoop install binaryen && scoop install wasmtime@29.0.1
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.24'
|
go-version: '1.25.7'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|||||||
+2
-2
@@ -16,13 +16,13 @@
|
|||||||
url = https://github.com/WebAssembly/wasi-libc
|
url = https://github.com/WebAssembly/wasi-libc
|
||||||
[submodule "lib/picolibc"]
|
[submodule "lib/picolibc"]
|
||||||
path = lib/picolibc
|
path = lib/picolibc
|
||||||
url = https://github.com/keith-packard/picolibc.git
|
url = https://github.com/picolibc/picolibc.git
|
||||||
[submodule "lib/stm32-svd"]
|
[submodule "lib/stm32-svd"]
|
||||||
path = lib/stm32-svd
|
path = lib/stm32-svd
|
||||||
url = https://github.com/tinygo-org/stm32-svd
|
url = https://github.com/tinygo-org/stm32-svd
|
||||||
[submodule "lib/musl"]
|
[submodule "lib/musl"]
|
||||||
path = lib/musl
|
path = lib/musl
|
||||||
url = git://git.musl-libc.org/musl
|
url = https://github.com/tinygo-org/musl-libc.git
|
||||||
[submodule "lib/binaryen"]
|
[submodule "lib/binaryen"]
|
||||||
path = lib/binaryen
|
path = lib/binaryen
|
||||||
url = https://github.com/WebAssembly/binaryen.git
|
url = https://github.com/WebAssembly/binaryen.git
|
||||||
|
|||||||
+8
-2
@@ -85,11 +85,17 @@ Try running TinyGo:
|
|||||||
|
|
||||||
./build/tinygo help
|
./build/tinygo help
|
||||||
|
|
||||||
Also, make sure the `tinygo` binary really is statically linked. Check this
|
Also, make sure the `tinygo` binary really is statically linked. The command to check for
|
||||||
using `ldd` (not to be confused with `lld`):
|
dynamic dependencies differs depending on your operating system.
|
||||||
|
|
||||||
|
On Linux, use `ldd` (not to be confused with `lld`):
|
||||||
|
|
||||||
ldd ./build/tinygo
|
ldd ./build/tinygo
|
||||||
|
|
||||||
|
On macOS, use otool -L:
|
||||||
|
|
||||||
|
otool -L ./build/tinygo
|
||||||
|
|
||||||
The result should not contain libclang or libLLVM.
|
The result should not contain libclang or libLLVM.
|
||||||
|
|
||||||
## Make a release tarball
|
## Make a release tarball
|
||||||
|
|||||||
+153
@@ -1,3 +1,156 @@
|
|||||||
|
0.40.1
|
||||||
|
---
|
||||||
|
* **machine**
|
||||||
|
- nrf: fix flash writes when SoftDevice is enabled
|
||||||
|
* **runtime**
|
||||||
|
- runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
|
||||||
|
- runtime: add calls to initRand() during run() for all schedulers
|
||||||
|
- runtime: call initRand() before initHeap() during initialization
|
||||||
|
- runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
|
||||||
|
* **libs**
|
||||||
|
- picolibc: use updated location for git repo
|
||||||
|
|
||||||
|
0.40.0
|
||||||
|
---
|
||||||
|
* **general**
|
||||||
|
- all: add full LLVM 20 support
|
||||||
|
- core: feat: enable //go:linkname pragma for globals
|
||||||
|
- core: feature: Add flag to ignore go compatibility matrix (#5078)
|
||||||
|
- chore: update version for 0.40 development cycle
|
||||||
|
* **compiler**
|
||||||
|
- emit an error when the actual arch doesn't match GOARCH
|
||||||
|
- mark string parameters as readonly
|
||||||
|
- use Tarjan's SCC algorithm to detect loops for defer
|
||||||
|
- lower "large stack" limit to 16kb
|
||||||
|
* **core**
|
||||||
|
- shrink bdwgc library
|
||||||
|
- Fix linker errors for runtime.vgetrandom and crypto/internal/sysrand.fatal
|
||||||
|
- fix: add TryLock to sync.RWMutex
|
||||||
|
- fix: correct linter issues exposed by the fix in #4679
|
||||||
|
- fix: don't hardcode success return state
|
||||||
|
- fix: expand RTT debugger compatibility
|
||||||
|
- internal/task (threads): save stack bounds instead of scanning under a lock
|
||||||
|
- internal/task: create detached threads and fix error handling
|
||||||
|
- interp: better errors when debugging interp
|
||||||
|
- transform (gc): create stack slots in callers of external functions
|
||||||
|
- internal/task: prevent semaphore resource leak for threads scheduler
|
||||||
|
* **machine**
|
||||||
|
- cortexm: optimize code size for the HardFault_Handler
|
||||||
|
- fe310: add I2C pins for the HiFive1b
|
||||||
|
- clarify WriteAt semantics of BlockDevice
|
||||||
|
- fix deprecated AsmFull comment (#5005)
|
||||||
|
- make sure DMA buffers do not escape unnecessarily
|
||||||
|
- only enable USB-CDC when needed
|
||||||
|
- use larger SPI MAXCNT on nrf52833 and nrf52840
|
||||||
|
- fix: update m.queuedBytes when clamping output to avoid corrupting sentBytes
|
||||||
|
- fix: use int64 in ReadTemperature to avoid overflow
|
||||||
|
- fix(rp2): disable DBGPAUSE on startup
|
||||||
|
- fix(rp2): possible integer overflow while computing factors for SPI baudrate
|
||||||
|
- fix(rp2): reset spinlocks at startup
|
||||||
|
- fix(rp2): switch spinlock busy loop to wfe
|
||||||
|
- fix(rp2): use side-effect-free spinlocks
|
||||||
|
- nrf: add ADC_VDDH which is an ADC pin for VDDH
|
||||||
|
- nrf: don't block SPI transfer
|
||||||
|
- nrf: don't set PSELN, it's ignored in single ended mode anyway
|
||||||
|
- nrf: fix typo in ADC configuration
|
||||||
|
- nrf: refactor SoftDevice enabled check
|
||||||
|
- nrf: rename pwmPin to adcPin
|
||||||
|
- nrf: support flash operations while the SoftDevice is enabled
|
||||||
|
- rp2040: allow writing to the UART inside interrupts
|
||||||
|
- machine,nrf528: stop the bus only once on I2C bus error and ensures the first error is returned
|
||||||
|
* **net**
|
||||||
|
- update submodule to latest commits
|
||||||
|
* **runtime**
|
||||||
|
- (avr): fix infinite longjmp loop if stack is aligned to 256 bytes
|
||||||
|
- (gc_blocks.go): clear full size of allocation
|
||||||
|
- (gc_blocks.go): make sweep branchless
|
||||||
|
- (gc_blocks.go): simplify scanning logic
|
||||||
|
- (gc_blocks.go): use a linked stack to scan marked objects
|
||||||
|
- (gc_blocks.go): use best-fit allocation
|
||||||
|
- (gc_boehm.go): fix world already stopped check
|
||||||
|
- (wasm): scan the system stack
|
||||||
|
- fix sleep duration for long sleeps
|
||||||
|
- remove copied code for nrf52840
|
||||||
|
- src/syscall: update src buffer after write
|
||||||
|
- wasm: fix C realloc and optimize it a bit
|
||||||
|
* **targets**
|
||||||
|
- add xiao-esp32s3 board target
|
||||||
|
- Add ESP32-S3 support (#5091)
|
||||||
|
- Added Gopher ARCADE board
|
||||||
|
- Create "pico2-ice" target board (#5062)
|
||||||
|
* **build/test**
|
||||||
|
- Add testing.T.Context() and testing.B.Context()
|
||||||
|
- create separate go.mod file for testing dependencies for wasm tests that use Chromium headless browser to avoid use of older incompatible version.
|
||||||
|
- go back to normal scheduler instead of tasks scheduler for macos CI
|
||||||
|
- update CI to use Go 1.25.5
|
||||||
|
- update macOS GH actions builds to handle sunset of macOS 13
|
||||||
|
- use task scheduler on macOS builds to avoid test race condition lockups
|
||||||
|
- update all CI builds to use latest stable Go release. Also update some of the actions to their latest releases.
|
||||||
|
- update GH actions builds to use Go 1.25.4
|
||||||
|
- uninstall cmake before install
|
||||||
|
- fix: point the submodule for musl-lib to a mirror in the TinyGo GitHub org
|
||||||
|
- fix: remove macOS 15 from CI build matrix (conflicts with macOS 14 build)
|
||||||
|
- fix: separate host expected bytes from device intended bytes
|
||||||
|
- fix/typo: makeESPFirmwareImage
|
||||||
|
- make: GNUmakefile: shrink TinyGo binaries on Linux
|
||||||
|
- move the directory list into a variable
|
||||||
|
- several improvements to the macOS GH actions build
|
||||||
|
- Fix for #4678: top-level 'make lint' wasn't working
|
||||||
|
- fix: increase the timeout for chromedp to connect to the headless browser used for running the wasm tests.
|
||||||
|
- testdata: some more packages for the test corpus
|
||||||
|
|
||||||
|
0.39.0
|
||||||
|
---
|
||||||
|
* **general**
|
||||||
|
- all: add Go 1.25 support
|
||||||
|
- net: update to latest tinygo net package
|
||||||
|
- docs: clarify build verification step for macOS users
|
||||||
|
- Add flag to skip Renesas SVD builds
|
||||||
|
* **build**
|
||||||
|
- Makefile: install missing dlmalloc files
|
||||||
|
- flash: add -o flag support to save built binary (Fixes #4937) (#4942)
|
||||||
|
- fix: update version of clang to 17 to accommodate latest Go 1.25 docker base image
|
||||||
|
* **ci**
|
||||||
|
- chore: update all CI builds to test Go 1.25 release
|
||||||
|
- fix: disable test-newest since CircleCI seems unable to download due to rate-limits on Dockerhub
|
||||||
|
- ci: rename some jobs to avoid churn on every Go/LLVM version bump
|
||||||
|
- ci: make the goroutines test less racy
|
||||||
|
- tests: de-flake goroutines test
|
||||||
|
* **compiler**
|
||||||
|
- compiler: implement internal/abi.Escape
|
||||||
|
* **main**
|
||||||
|
- main: show the compiler error (if any) for `tinygo test -c`
|
||||||
|
- chore: correct GOOS=js name in error messages for WASM
|
||||||
|
* **machine**
|
||||||
|
- machine: add international keys
|
||||||
|
- machine: remove some unnecessary "// peripherals:" comments
|
||||||
|
- machine: add I2C pin comments
|
||||||
|
- machine: standardize I2C errors with "i2c:" prefix
|
||||||
|
- machine: make I2C usable in the simulator
|
||||||
|
- fix: add SPI and I2C to teensy 4.1 (#4943)
|
||||||
|
- `rp2`: use the correct channel mask for rp2350 ADC; hold lock during read (#4938)
|
||||||
|
- `rp2`: disable digital input for analog inputs
|
||||||
|
* **runtime**
|
||||||
|
- runtime: ensure time.Sleep(d) sleeps at least d
|
||||||
|
- runtime: stub out weak pointer support
|
||||||
|
- runtime: implement dummy AddCleanup
|
||||||
|
- runtime: enable multi-core scheduler for rp2350
|
||||||
|
- `internal/task`: use -stack-size flag when starting a new thread
|
||||||
|
- `internal/task`: add SA_RESTART flag to GC interrupts
|
||||||
|
- `internal/task`: a few small correctness fixes
|
||||||
|
- `internal/gclayout`: make gclayout values constants
|
||||||
|
- darwin: add threading support and use it by default
|
||||||
|
* **standard library**
|
||||||
|
- `sync`: implement sync.Swap
|
||||||
|
- `reflect`: implement Method.IsExported
|
||||||
|
* **testing**
|
||||||
|
- testing: stub out testing.B.Loop
|
||||||
|
* **targets**
|
||||||
|
- `stm32`: add support for the STM32L031G6U6
|
||||||
|
- add metro-rp2350 board definition (#4989)
|
||||||
|
- `rp2040/rp2350`: set the default stack size to 8k for rp2040/rp2350 based boards where this was not already the case
|
||||||
|
|
||||||
|
|
||||||
0.38.0
|
0.38.0
|
||||||
---
|
---
|
||||||
* **general**
|
* **general**
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||||
FROM golang:1.24 AS tinygo-llvm
|
FROM golang:1.25 AS tinygo-llvm
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
|
apt-get install -y apt-utils make cmake clang-17 ninja-build && \
|
||||||
rm -rf \
|
rm -rf \
|
||||||
/var/lib/apt/lists/* \
|
/var/lib/apt/lists/* \
|
||||||
/var/log/* \
|
/var/log/* \
|
||||||
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
|
|||||||
|
|
||||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||||
# all the build tools etc).
|
# all the build tools etc).
|
||||||
FROM golang:1.24 AS tinygo-compiler
|
FROM golang:1.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
|
||||||
|
|||||||
+68
-14
@@ -79,6 +79,26 @@ ifeq (1, $(STATIC))
|
|||||||
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
|
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Optimize the binary size for Linux.
|
||||||
|
# These flags may work on other platforms, but have only been tested on Linux.
|
||||||
|
ifeq ($(uname),Linux)
|
||||||
|
HAS_MOLD := $(shell command -v ld.mold 2> /dev/null)
|
||||||
|
HAS_LLD := $(shell command -v ld.lld 2> /dev/null)
|
||||||
|
LLVM_CFLAGS := -ffunction-sections -fdata-sections -fvisibility=hidden
|
||||||
|
LLVM_LDFLAGS := -Wl,--gc-sections
|
||||||
|
ifneq ($(HAS_MOLD),)
|
||||||
|
# Mold might be slightly faster.
|
||||||
|
LLVM_LDFLAGS += -fuse-ld=mold -Wl,--icf=all
|
||||||
|
else ifneq ($(HAS_LLD),)
|
||||||
|
# LLD is more commonly available.
|
||||||
|
LLVM_LDFLAGS += -fuse-ld=lld -Wl,--icf=all
|
||||||
|
endif
|
||||||
|
LLVM_OPTION += \
|
||||||
|
-DCMAKE_C_FLAGS="$(LLVM_CFLAGS)" \
|
||||||
|
-DCMAKE_CXX_FLAGS="$(LLVM_CFLAGS)"
|
||||||
|
CGO_LDFLAGS += $(LLVM_LDFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
# Cross compiling support.
|
# Cross compiling support.
|
||||||
ifneq ($(CROSS),)
|
ifneq ($(CROSS),)
|
||||||
CC = $(CROSS)-gcc
|
CC = $(CROSS)-gcc
|
||||||
@@ -187,7 +207,10 @@ fmt-check: ## Warn if any source needs reformatting
|
|||||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||||
|
|
||||||
|
|
||||||
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp gen-device-renesas ## Generate microcontroller-specific sources
|
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp ## Generate microcontroller-specific sources
|
||||||
|
ifneq ($(RENESAS), 0)
|
||||||
|
gen-device: gen-device-renesas
|
||||||
|
endif
|
||||||
ifneq ($(STM32), 0)
|
ifneq ($(STM32), 0)
|
||||||
gen-device: gen-device-stm32
|
gen-device: gen-device-stm32
|
||||||
endif
|
endif
|
||||||
@@ -240,7 +263,7 @@ gen-device-renesas: build/gen-device-svd
|
|||||||
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
||||||
|
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
git clone -b xtensa_release_19.1.2 --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
git clone -b tinygo_20.x --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||||
llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources
|
llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources
|
||||||
|
|
||||||
# Configure LLVM.
|
# Configure LLVM.
|
||||||
@@ -457,11 +480,16 @@ 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'
|
||||||
|
TEST_ADDITIONAL_FLAGS ?=
|
||||||
|
|
||||||
# Test known-working standard library packages.
|
# Test known-working standard library packages.
|
||||||
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
||||||
.PHONY: tinygo-test
|
.PHONY: tinygo-test
|
||||||
tinygo-test:
|
tinygo-test:
|
||||||
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
@# TestExtraMethods: used by many crypto packages and uses reflect.Type.Method which is not implemented.
|
||||||
|
@# TestParseAndBytesRoundTrip/P256/Generic: relies on t.Skip() which is not implemented
|
||||||
|
$(TINYGO) test $(TEST_ADDITIONAL_FLAGS) $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
||||||
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
|
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
|
||||||
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
||||||
@# For more details, see the comments on issue #3143.
|
@# For more details, see the comments on issue #3143.
|
||||||
@@ -469,7 +497,7 @@ ifeq ($(TEST_IOFS),true)
|
|||||||
$(TINYGO) test -stack-size=6MB io/fs
|
$(TINYGO) test -stack-size=6MB io/fs
|
||||||
endif
|
endif
|
||||||
tinygo-test-fast:
|
tinygo-test-fast:
|
||||||
$(TINYGO) test $(TEST_PACKAGES_HOST)
|
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST)
|
||||||
tinygo-bench:
|
tinygo-bench:
|
||||||
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-bench-fast:
|
tinygo-bench-fast:
|
||||||
@@ -477,18 +505,18 @@ tinygo-bench-fast:
|
|||||||
|
|
||||||
# Same thing, except for wasi rather than the current platform.
|
# Same thing, except for wasi rather than the current platform.
|
||||||
tinygo-test-wasm:
|
tinygo-test-wasm:
|
||||||
$(TINYGO) test -target wasm $(TEST_PACKAGES_WASM)
|
$(TINYGO) test -target wasm $(TEST_SKIP_FLAG) $(TEST_PACKAGES_WASM)
|
||||||
tinygo-test-wasi:
|
tinygo-test-wasi:
|
||||||
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
$(TINYGO) test -target wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
tinygo-test-wasip1:
|
tinygo-test-wasip1:
|
||||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
tinygo-test-wasip1-fast:
|
tinygo-test-wasip1-fast:
|
||||||
$(TINYGO) test -target=wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
$(TINYGO) test -target=wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
|
|
||||||
tinygo-test-wasip2-slow:
|
tinygo-test-wasip2-slow:
|
||||||
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-test-wasip2-fast:
|
tinygo-test-wasip2-fast:
|
||||||
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
|
|
||||||
tinygo-test-wasip2-sum-slow:
|
tinygo-test-wasip2-sum-slow:
|
||||||
TINYGO=$(TINYGO) \
|
TINYGO=$(TINYGO) \
|
||||||
@@ -514,7 +542,7 @@ tinygo-bench-wasip2-fast:
|
|||||||
|
|
||||||
# Run tests on riscv-qemu since that one provides a large amount of memory.
|
# Run tests on riscv-qemu since that one provides a large amount of memory.
|
||||||
tinygo-test-baremetal:
|
tinygo-test-baremetal:
|
||||||
$(TINYGO) test -target riscv-qemu $(TEST_PACKAGES_BAREMETAL)
|
$(TINYGO) test -target riscv-qemu $(TEST_SKIP_FLAG) $(TEST_PACKAGES_BAREMETAL)
|
||||||
|
|
||||||
# Test external packages in a large corpus.
|
# Test external packages in a large corpus.
|
||||||
test-corpus:
|
test-corpus:
|
||||||
@@ -594,6 +622,8 @@ smoketest: testchdir
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test simulated boards on play.tinygo.org
|
# 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 examples/blinky1
|
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||||
@@ -768,6 +798,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=gopher-arcade examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
||||||
@@ -778,8 +810,12 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=metro-rp2350 examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
|
$(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
|
||||||
# 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
|
||||||
@@ -837,6 +873,8 @@ ifneq ($(STM32), 0)
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
|
||||||
|
@$(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
|
||||||
@@ -860,6 +898,10 @@ 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)
|
||||||
@@ -879,6 +921,12 @@ 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
|
||||||
|
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
|
||||||
|
@$(MD5SUM) test.bin
|
||||||
|
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008
|
||||||
|
@$(MD5SUM) test.bin
|
||||||
|
$(TINYGO) build -size short -o test.bin -target=esp32s3-wroom1 examples/mcp3008
|
||||||
|
@$(MD5SUM) test.bin
|
||||||
endif
|
endif
|
||||||
$(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
|
||||||
@@ -907,7 +955,7 @@ endif
|
|||||||
$(TINYGO) build -size short -o test.hex -target=hw-651 examples/machinetest
|
$(TINYGO) build -size short -o test.hex -target=hw-651 examples/machinetest
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=hw-651-s110v8 examples/machinetest
|
$(TINYGO) build -size short -o test.hex -target=hw-651-s110v8 examples/machinetest
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
||||||
@@ -940,7 +988,7 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
wasmtest:
|
wasmtest:
|
||||||
$(GO) test ./tests/wasm
|
cd ./tests/wasm && $(GO) test .
|
||||||
|
|
||||||
build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
|
build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
|
||||||
@mkdir -p build/release/tinygo/bin
|
@mkdir -p build/release/tinygo/bin
|
||||||
@@ -958,6 +1006,7 @@ build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binary
|
|||||||
@mkdir -p build/release/tinygo/lib/nrfx
|
@mkdir -p build/release/tinygo/lib/nrfx
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
|
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
|
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
|
@mkdir -p build/release/tinygo/lib/wasi-libc/dlmalloc
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
@@ -1029,6 +1078,7 @@ endif
|
|||||||
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
|
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
||||||
|
@cp -rp lib/wasi-libc/dlmalloc/src build/release/tinygo/lib/wasi-libc/dlmalloc
|
||||||
@cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@cp -rp lib/wasi-libc/libc-bottom-half/headers build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@cp -rp lib/wasi-libc/libc-bottom-half/headers build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@cp -rp lib/wasi-libc/libc-bottom-half/sources build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@cp -rp lib/wasi-libc/libc-bottom-half/sources build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@@ -1085,6 +1135,7 @@ endif
|
|||||||
tools:
|
tools:
|
||||||
cd internal/tools && go generate -tags tools ./
|
cd internal/tools && go generate -tags tools ./
|
||||||
|
|
||||||
|
LINTDIRS=src/os/ src/reflect/
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: tools ## Lint source tree
|
lint: tools ## Lint source tree
|
||||||
revive -version
|
revive -version
|
||||||
@@ -1092,7 +1143,10 @@ lint: tools ## Lint source tree
|
|||||||
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
|
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
|
||||||
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
|
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
|
||||||
# Use 'grep .' to get rid of stray blank line
|
# Use 'grep .' to get rid of stray blank line
|
||||||
revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
|
revive -config revive.toml compiler/... $$( find $(LINTDIRS) -type f -name '*.go' ) \
|
||||||
|
| grep -v "should have comment or be unexported" \
|
||||||
|
| grep '.' \
|
||||||
|
| awk '{print}; END {exit NR>0}'
|
||||||
|
|
||||||
SPELLDIRSCMD=find . -depth 1 -type d | egrep -wv '.git|lib|llvm|src'; find src -depth 1 | egrep -wv 'device|internal|net|vendor'; find src/internal -depth 1 -type d | egrep -wv src/internal/wasi
|
SPELLDIRSCMD=find . -depth 1 -type d | egrep -wv '.git|lib|llvm|src'; find src -depth 1 | egrep -wv 'device|internal|net|vendor'; find src/internal -depth 1 -type d | egrep -wv src/internal/wasi
|
||||||
.PHONY: spell
|
.PHONY: spell
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
Copyright (c) 2018-2025 The TinyGo Authors. All rights reserved.
|
Copyright (c) 2018-2026 The TinyGo Authors. All rights reserved.
|
||||||
|
|
||||||
TinyGo includes portions of the Go standard library.
|
TinyGo includes portions of the Go standard library.
|
||||||
Copyright (c) 2009-2024 The Go Authors. All rights reserved.
|
Copyright 2009 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,6 +6,9 @@ TinyGo is a Go compiler intended for use in small places such as microcontroller
|
|||||||
|
|
||||||
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:
|
||||||
@@ -63,7 +66,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
|
||||||
GOARCH=wasip1 GOOS=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
GOOS=wasip1 GOARCH=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|||||||
+6
-3
@@ -30,7 +30,10 @@ var BoehmGC = Library{
|
|||||||
// Use a minimal environment.
|
// Use a minimal environment.
|
||||||
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
|
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
|
||||||
"-DDONT_USE_ATEXIT",
|
"-DDONT_USE_ATEXIT",
|
||||||
"-DNO_GETENV",
|
"-DNO_GETENV", // smaller binary, more predictable configuration
|
||||||
|
"-DNO_CLOCK", // don't use system clock
|
||||||
|
"-DNO_DEBUGGING", // reduce code size
|
||||||
|
"-DGC_NO_FINALIZATION", // finalization is not used at the moment
|
||||||
|
|
||||||
// Special flag to work around the lack of __data_start in ld.lld.
|
// Special flag to work around the lack of __data_start in ld.lld.
|
||||||
// TODO: try to fix this in LLVM/lld directly so we don't have to
|
// TODO: try to fix this in LLVM/lld directly so we don't have to
|
||||||
@@ -39,6 +42,8 @@ var BoehmGC = Library{
|
|||||||
|
|
||||||
// Do not scan the stack. We have our own mechanism to do this.
|
// Do not scan the stack. We have our own mechanism to do this.
|
||||||
"-DSTACK_NOT_SCANNED",
|
"-DSTACK_NOT_SCANNED",
|
||||||
|
"-DNO_PROC_STAT", // we scan the stack manually (don't read /proc/self/stat on Linux)
|
||||||
|
"-DSTACKBOTTOM=0", // dummy value, we scan the stack manually
|
||||||
|
|
||||||
// Assertions can be enabled while debugging GC issues.
|
// Assertions can be enabled while debugging GC issues.
|
||||||
//"-DGC_ASSERTIONS",
|
//"-DGC_ASSERTIONS",
|
||||||
@@ -63,7 +68,6 @@ var BoehmGC = Library{
|
|||||||
"blacklst.c",
|
"blacklst.c",
|
||||||
"dbg_mlc.c",
|
"dbg_mlc.c",
|
||||||
"dyn_load.c",
|
"dyn_load.c",
|
||||||
"finalize.c",
|
|
||||||
"headers.c",
|
"headers.c",
|
||||||
"mach_dep.c",
|
"mach_dep.c",
|
||||||
"malloc.c",
|
"malloc.c",
|
||||||
@@ -71,7 +75,6 @@ var BoehmGC = Library{
|
|||||||
"mark_rts.c",
|
"mark_rts.c",
|
||||||
"misc.c",
|
"misc.c",
|
||||||
"new_hblk.c",
|
"new_hblk.c",
|
||||||
"obj_map.c",
|
|
||||||
"os_dep.c",
|
"os_dep.c",
|
||||||
"reclaim.c",
|
"reclaim.c",
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-6
@@ -19,6 +19,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -281,9 +282,13 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for name, files := range allFiles {
|
// Sort embedded files by name to maintain output determinism.
|
||||||
name := name
|
embedNames := make([]string, 0, len(allFiles))
|
||||||
files := files
|
for _, files := range allFiles {
|
||||||
|
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 {
|
||||||
@@ -298,7 +303,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 files {
|
for _, file := range allFiles[name] {
|
||||||
file.Size = uint64(len(data))
|
file.Size = uint64(len(data))
|
||||||
file.Hash = hexSum
|
file.Hash = hexSum
|
||||||
if file.NeedsData {
|
if file.NeedsData {
|
||||||
@@ -1042,11 +1047,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
case "esp32", "esp32-img", "esp32c3", "esp8266":
|
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp8266":
|
||||||
// Special format for the ESP family of chips (parsed by the ROM
|
// Special format for the ESP family of chips (parsed by the ROM
|
||||||
// bootloader).
|
// bootloader).
|
||||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||||
err := makeESPFirmareImage(result.Executable, result.Binary, outputBinaryFormat)
|
err := makeESPFirmwareImage(result.Executable, result.Binary, outputBinaryFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
"cortex-m4",
|
"cortex-m4",
|
||||||
"cortex-m7",
|
"cortex-m7",
|
||||||
"esp32c3",
|
"esp32c3",
|
||||||
|
"esp32s3",
|
||||||
"fe310",
|
"fe310",
|
||||||
"gameboy-advance",
|
"gameboy-advance",
|
||||||
"k210",
|
"k210",
|
||||||
|
|||||||
+13
-8
@@ -144,8 +144,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
.Default(llvm::DebugCompressionType::None);
|
.Default(llvm::DebugCompressionType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
|
|
||||||
Opts.SSE2AVX = Args.hasArg(OPT_msse2avx);
|
|
||||||
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
|
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
|
||||||
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
|
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
|
||||||
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
|
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
|
||||||
@@ -236,6 +234,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
Opts.EmitCompactUnwindNonCanonical =
|
Opts.EmitCompactUnwindNonCanonical =
|
||||||
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
||||||
Opts.Crel = Args.hasArg(OPT_crel);
|
Opts.Crel = Args.hasArg(OPT_crel);
|
||||||
|
Opts.ImplicitMapsyms = Args.hasArg(OPT_mmapsyms_implicit);
|
||||||
|
Opts.X86RelaxRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
|
||||||
|
Opts.X86Sse2Avx = Args.hasArg(OPT_msse2avx);
|
||||||
|
|
||||||
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
||||||
|
|
||||||
@@ -294,8 +295,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
||||||
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
|
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
|
||||||
MCOptions.Crel = Opts.Crel;
|
MCOptions.Crel = Opts.Crel;
|
||||||
MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations;
|
MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
|
||||||
MCOptions.X86Sse2Avx = Opts.SSE2AVX;
|
MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
|
||||||
|
MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
|
||||||
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
|
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
|
||||||
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
||||||
|
|
||||||
@@ -343,10 +345,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||||
std::unique_ptr<MCObjectFileInfo> MOFI(
|
std::unique_ptr<MCObjectFileInfo> MOFI(
|
||||||
TheTarget->createMCObjectFileInfo(Ctx, PIC));
|
TheTarget->createMCObjectFileInfo(Ctx, PIC));
|
||||||
if (Opts.DarwinTargetVariantTriple)
|
|
||||||
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
|
|
||||||
if (!Opts.DarwinTargetVariantSDKVersion.empty())
|
|
||||||
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
|
|
||||||
Ctx.setObjectFileInfo(MOFI.get());
|
Ctx.setObjectFileInfo(MOFI.get());
|
||||||
|
|
||||||
if (Opts.GenDwarfForAssembly)
|
if (Opts.GenDwarfForAssembly)
|
||||||
@@ -428,6 +426,13 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
Str.reset(TheTarget->createMCObjectStreamer(
|
Str.reset(TheTarget->createMCObjectStreamer(
|
||||||
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
|
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
|
||||||
Str.get()->initSections(Opts.NoExecStack, *STI);
|
Str.get()->initSections(Opts.NoExecStack, *STI);
|
||||||
|
if (T.isOSBinFormatMachO() && T.isOSDarwin()) {
|
||||||
|
Triple *TVT = Opts.DarwinTargetVariantTriple
|
||||||
|
? &*Opts.DarwinTargetVariantTriple
|
||||||
|
: nullptr;
|
||||||
|
Str->emitVersionForTarget(T, VersionTuple(), TVT,
|
||||||
|
Opts.DarwinTargetVariantSDKVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
||||||
|
|||||||
+10
-5
@@ -45,10 +45,6 @@ struct AssemblerInvocation {
|
|||||||
LLVM_PREFERRED_TYPE(bool)
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
unsigned GenDwarfForAssembly : 1;
|
unsigned GenDwarfForAssembly : 1;
|
||||||
LLVM_PREFERRED_TYPE(bool)
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
unsigned RelaxELFRelocations : 1;
|
|
||||||
LLVM_PREFERRED_TYPE(bool)
|
|
||||||
unsigned SSE2AVX : 1;
|
|
||||||
LLVM_PREFERRED_TYPE(bool)
|
|
||||||
unsigned Dwarf64 : 1;
|
unsigned Dwarf64 : 1;
|
||||||
unsigned DwarfVersion;
|
unsigned DwarfVersion;
|
||||||
std::string DwarfDebugFlags;
|
std::string DwarfDebugFlags;
|
||||||
@@ -117,6 +113,13 @@ struct AssemblerInvocation {
|
|||||||
|
|
||||||
LLVM_PREFERRED_TYPE(bool)
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
unsigned Crel : 1;
|
unsigned Crel : 1;
|
||||||
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
|
unsigned ImplicitMapsyms : 1;
|
||||||
|
|
||||||
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
|
unsigned X86RelaxRelocations : 1;
|
||||||
|
LLVM_PREFERRED_TYPE(bool)
|
||||||
|
unsigned X86Sse2Avx : 1;
|
||||||
|
|
||||||
/// The name of the relocation model to use.
|
/// The name of the relocation model to use.
|
||||||
std::string RelocationModel;
|
std::string RelocationModel;
|
||||||
@@ -148,7 +151,6 @@ public:
|
|||||||
ShowInst = 0;
|
ShowInst = 0;
|
||||||
ShowEncoding = 0;
|
ShowEncoding = 0;
|
||||||
RelaxAll = 0;
|
RelaxAll = 0;
|
||||||
SSE2AVX = 0;
|
|
||||||
NoExecStack = 0;
|
NoExecStack = 0;
|
||||||
FatalWarnings = 0;
|
FatalWarnings = 0;
|
||||||
NoWarn = 0;
|
NoWarn = 0;
|
||||||
@@ -160,6 +162,9 @@ public:
|
|||||||
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
||||||
EmitCompactUnwindNonCanonical = false;
|
EmitCompactUnwindNonCanonical = false;
|
||||||
Crel = false;
|
Crel = false;
|
||||||
|
ImplicitMapsyms = 0;
|
||||||
|
X86RelaxRelocations = 0;
|
||||||
|
X86Sse2Avx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ bool tinygo_clang_driver(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the actual diagnostics engine.
|
// Create the actual diagnostics engine.
|
||||||
Clang->createDiagnostics();
|
Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
|
||||||
if (!Clang->hasDiagnostics()) {
|
if (!Clang->hasDiagnostics()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -26,17 +26,20 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
|
|
||||||
// Version range supported by TinyGo.
|
// Version range supported by TinyGo.
|
||||||
const minorMin = 19
|
const minorMin = 19
|
||||||
const minorMax = 24
|
const minorMax = 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()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
|
||||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
if options.GoCompatibility {
|
||||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||||
|
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||||
|
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the Go toolchain version isn't too new, if we haven't been
|
// Check that the Go toolchain version isn't too new, if we haven't been
|
||||||
|
|||||||
+4
-3
@@ -23,7 +23,7 @@ type espImageSegment struct {
|
|||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
|
// makeESPFirmwareImage converts an input ELF file to an image file for an ESP32 or
|
||||||
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
||||||
// family, and is parsed by the on-chip mask ROM bootloader.
|
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||||
//
|
//
|
||||||
@@ -31,7 +31,7 @@ type espImageSegment struct {
|
|||||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
||||||
// https://github.com/espressif/esptool/blob/master/esptool.py
|
// https://github.com/espressif/esptool/blob/master/esptool.py
|
||||||
func makeESPFirmareImage(infile, outfile, format string) error {
|
func makeESPFirmwareImage(infile, outfile, format string) error {
|
||||||
inf, err := elf.Open(infile)
|
inf, err := elf.Open(infile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -100,11 +100,12 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
|||||||
chip_id := map[string]uint16{
|
chip_id := map[string]uint16{
|
||||||
"esp32": 0x0000,
|
"esp32": 0x0000,
|
||||||
"esp32c3": 0x0005,
|
"esp32c3": 0x0005,
|
||||||
|
"esp32s3": 0x0009,
|
||||||
}[chip]
|
}[chip]
|
||||||
|
|
||||||
// Image header.
|
// Image header.
|
||||||
switch chip {
|
switch chip {
|
||||||
case "esp32", "esp32c3":
|
case "esp32", "esp32c3", "esp32s3":
|
||||||
// Header format:
|
// Header format:
|
||||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
||||||
// Note: not adding a SHA256 hash as the binary is modified by
|
// Note: not adding a SHA256 hash as the binary is modified by
|
||||||
|
|||||||
@@ -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", 4556, 280, 0, 2264},
|
{"hifive1b", "examples/echo", 3668, 280, 0, 2244},
|
||||||
{"microbit", "examples/serial", 2920, 388, 8, 2272},
|
{"microbit", "examples/serial", 2694, 342, 8, 2248},
|
||||||
{"wioterminal", "examples/pininterrupt", 7379, 1489, 116, 6912},
|
{"wioterminal", "examples/pininterrupt", 6837, 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
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ func (c *Config) StackSize() uint64 {
|
|||||||
|
|
||||||
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
|
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
|
||||||
func (c *Config) MaxStackAlloc() uint64 {
|
func (c *Config) MaxStackAlloc() uint64 {
|
||||||
if c.StackSize() > 32*1024 {
|
if c.StackSize() >= 16*1024 {
|
||||||
return 1024
|
return 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type Options struct {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
case "wasip2":
|
case "wasip2":
|
||||||
options.Target = "wasip2"
|
options.Target = "wasip2"
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("GOARCH=wasm but GOOS is not set correctly. Please set GOOS to wasm, wasip1, or wasip2.")
|
return nil, errors.New("GOARCH=wasm but GOOS is not set correctly. Please set GOOS to js, wasip1, or wasip2.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
|||||||
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
|
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
|
||||||
}
|
}
|
||||||
case "wasm":
|
case "wasm":
|
||||||
return nil, fmt.Errorf("GOARCH=wasm but GOOS is unset. Please set GOOS to wasm, wasip1, or wasip2.")
|
return nil, fmt.Errorf("GOARCH=wasm but GOOS is unset. Please set GOOS to js, wasip1, or wasip2.")
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
|
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
|
||||||
}
|
}
|
||||||
@@ -385,7 +385,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
|||||||
platformVersion = "11.0.0" // first macosx platform with arm64 support
|
platformVersion = "11.0.0" // first macosx platform with arm64 support
|
||||||
}
|
}
|
||||||
llvmvendor = "apple"
|
llvmvendor = "apple"
|
||||||
spec.Scheduler = "tasks"
|
spec.Scheduler = "threads"
|
||||||
spec.Linker = "ld.lld"
|
spec.Linker = "ld.lld"
|
||||||
spec.Libc = "darwin-libSystem"
|
spec.Libc = "darwin-libSystem"
|
||||||
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to
|
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to
|
||||||
@@ -399,6 +399,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
|||||||
)
|
)
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||||
"src/internal/futex/futex_darwin.c",
|
"src/internal/futex/futex_darwin.c",
|
||||||
|
"src/internal/task/task_threads.c",
|
||||||
"src/runtime/os_darwin.c",
|
"src/runtime/os_darwin.c",
|
||||||
"src/runtime/runtime_unix.c",
|
"src/runtime/runtime_unix.c",
|
||||||
"src/runtime/signal.c")
|
"src/runtime/signal.c")
|
||||||
|
|||||||
+1
-1
@@ -245,7 +245,7 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
|
|||||||
// current insert position.
|
// current insert position.
|
||||||
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||||
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
|
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
|
||||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
|
||||||
|
|
||||||
// Now branch to the out-of-bounds or the regular block.
|
// Now branch to the out-of-bounds or the regular block.
|
||||||
b.CreateCondBr(assert, faultBlock, nextBlock)
|
b.CreateCondBr(assert, faultBlock, nextBlock)
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ const (
|
|||||||
// Whether this is a full or partial Go parameter (int, slice, etc).
|
// Whether this is a full or partial Go parameter (int, slice, etc).
|
||||||
// The extra context parameter is not a Go parameter.
|
// The extra context parameter is not a Go parameter.
|
||||||
paramIsGoParam = 1 << iota
|
paramIsGoParam = 1 << iota
|
||||||
|
|
||||||
|
// Whether this is a readonly parameter (for example, a string pointer).
|
||||||
|
paramIsReadonly
|
||||||
)
|
)
|
||||||
|
|
||||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
||||||
@@ -167,6 +170,7 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
suffix := strconv.Itoa(i)
|
suffix := strconv.Itoa(i)
|
||||||
|
isString := false
|
||||||
if goType != nil {
|
if goType != nil {
|
||||||
// Try to come up with a good suffix for this struct field,
|
// Try to come up with a good suffix for this struct field,
|
||||||
// depending on which Go type it's based on.
|
// depending on which Go type it's based on.
|
||||||
@@ -183,12 +187,16 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
|||||||
suffix = []string{"r", "i"}[i]
|
suffix = []string{"r", "i"}[i]
|
||||||
case types.String:
|
case types.String:
|
||||||
suffix = []string{"data", "len"}[i]
|
suffix = []string{"data", "len"}[i]
|
||||||
|
isString = true
|
||||||
}
|
}
|
||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
suffix = []string{"context", "funcptr"}[i]
|
suffix = []string{"context", "funcptr"}[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||||
|
if isString {
|
||||||
|
subInfos[0].flags |= paramIsReadonly
|
||||||
|
}
|
||||||
paramInfos = append(paramInfos, subInfos...)
|
paramInfos = append(paramInfos, subInfos...)
|
||||||
}
|
}
|
||||||
return paramInfos
|
return paramInfos
|
||||||
|
|||||||
+137
-33
@@ -152,10 +152,12 @@ type builder struct {
|
|||||||
llvmFnType llvm.Type
|
llvmFnType llvm.Type
|
||||||
llvmFn llvm.Value
|
llvmFn llvm.Value
|
||||||
info functionInfo
|
info functionInfo
|
||||||
locals map[ssa.Value]llvm.Value // local variables
|
locals map[ssa.Value]llvm.Value // local variables
|
||||||
blockEntries map[*ssa.BasicBlock]llvm.BasicBlock // a *ssa.BasicBlock may be split up
|
blockInfo []blockInfo
|
||||||
blockExits map[*ssa.BasicBlock]llvm.BasicBlock // these are the exit blocks
|
|
||||||
currentBlock *ssa.BasicBlock
|
currentBlock *ssa.BasicBlock
|
||||||
|
currentBlockInfo *blockInfo
|
||||||
|
tarjanStack []uint
|
||||||
|
tarjanIndex uint
|
||||||
phis []phiNode
|
phis []phiNode
|
||||||
deferPtr llvm.Value
|
deferPtr llvm.Value
|
||||||
deferFrame llvm.Value
|
deferFrame llvm.Value
|
||||||
@@ -187,11 +189,22 @@ func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *bu
|
|||||||
info: c.getFunctionInfo(f),
|
info: c.getFunctionInfo(f),
|
||||||
locals: make(map[ssa.Value]llvm.Value),
|
locals: make(map[ssa.Value]llvm.Value),
|
||||||
dilocals: make(map[*types.Var]llvm.Metadata),
|
dilocals: make(map[*types.Var]llvm.Metadata),
|
||||||
blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
|
||||||
blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type blockInfo struct {
|
||||||
|
// entry is the LLVM basic block corresponding to the start of this *ssa.Block.
|
||||||
|
entry llvm.BasicBlock
|
||||||
|
|
||||||
|
// exit is the LLVM basic block corresponding to the end of this *ssa.Block.
|
||||||
|
// It will be different than entry if any of the block's instructions contain internal branches.
|
||||||
|
exit llvm.BasicBlock
|
||||||
|
|
||||||
|
// tarjan holds state for applying Tarjan's strongly connected components algorithm to the CFG.
|
||||||
|
// This is used by defer.go to determine whether to stack- or heap-allocate defer data.
|
||||||
|
tarjan tarjanNode
|
||||||
|
}
|
||||||
|
|
||||||
type deferBuiltin struct {
|
type deferBuiltin struct {
|
||||||
callName string
|
callName string
|
||||||
pos token.Pos
|
pos token.Pos
|
||||||
@@ -1220,14 +1233,29 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
// intrinsic (like an atomic operation). Create the entry block
|
// intrinsic (like an atomic operation). Create the entry block
|
||||||
// manually.
|
// manually.
|
||||||
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
||||||
} else {
|
// Intrinsics may create internal branches (e.g. nil checks).
|
||||||
for _, block := range b.fn.DomPreorder() {
|
// They will attempt to access b.currentBlockInfo to update the exit block.
|
||||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
// Create some fake block info for them to access.
|
||||||
b.blockEntries[block] = llvmBlock
|
blockInfo := []blockInfo{
|
||||||
b.blockExits[block] = llvmBlock
|
{
|
||||||
|
entry: entryBlock,
|
||||||
|
exit: entryBlock,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
b.blockInfo = blockInfo
|
||||||
|
b.currentBlockInfo = &blockInfo[0]
|
||||||
|
} else {
|
||||||
|
blocks := b.fn.Blocks
|
||||||
|
blockInfo := make([]blockInfo, len(blocks))
|
||||||
|
for _, block := range b.fn.DomPreorder() {
|
||||||
|
info := &blockInfo[block.Index]
|
||||||
|
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||||
|
info.entry = llvmBlock
|
||||||
|
info.exit = llvmBlock
|
||||||
|
}
|
||||||
|
b.blockInfo = blockInfo
|
||||||
// Normal functions have an entry block.
|
// Normal functions have an entry block.
|
||||||
entryBlock = b.blockEntries[b.fn.Blocks[0]]
|
entryBlock = blockInfo[0].entry
|
||||||
}
|
}
|
||||||
b.SetInsertPointAtEnd(entryBlock)
|
b.SetInsertPointAtEnd(entryBlock)
|
||||||
|
|
||||||
@@ -1323,8 +1351,9 @@ func (b *builder) createFunction() {
|
|||||||
if b.DumpSSA {
|
if b.DumpSSA {
|
||||||
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
||||||
}
|
}
|
||||||
b.SetInsertPointAtEnd(b.blockEntries[block])
|
|
||||||
b.currentBlock = block
|
b.currentBlock = block
|
||||||
|
b.currentBlockInfo = &b.blockInfo[block.Index]
|
||||||
|
b.SetInsertPointAtEnd(b.currentBlockInfo.entry)
|
||||||
for _, instr := range block.Instrs {
|
for _, instr := range block.Instrs {
|
||||||
if instr, ok := instr.(*ssa.DebugRef); ok {
|
if instr, ok := instr.(*ssa.DebugRef); ok {
|
||||||
if !b.Debug {
|
if !b.Debug {
|
||||||
@@ -1384,7 +1413,7 @@ func (b *builder) createFunction() {
|
|||||||
block := phi.ssa.Block()
|
block := phi.ssa.Block()
|
||||||
for i, edge := range phi.ssa.Edges {
|
for i, edge := range phi.ssa.Edges {
|
||||||
llvmVal := b.getValue(edge, getPos(phi.ssa))
|
llvmVal := b.getValue(edge, getPos(phi.ssa))
|
||||||
llvmBlock := b.blockExits[block.Preds[i]]
|
llvmBlock := b.blockInfo[block.Preds[i].Index].exit
|
||||||
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1498,11 +1527,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
|||||||
case *ssa.If:
|
case *ssa.If:
|
||||||
cond := b.getValue(instr.Cond, getPos(instr))
|
cond := b.getValue(instr.Cond, getPos(instr))
|
||||||
block := instr.Block()
|
block := instr.Block()
|
||||||
blockThen := b.blockEntries[block.Succs[0]]
|
blockThen := b.blockInfo[block.Succs[0].Index].entry
|
||||||
blockElse := b.blockEntries[block.Succs[1]]
|
blockElse := b.blockInfo[block.Succs[1].Index].entry
|
||||||
b.CreateCondBr(cond, blockThen, blockElse)
|
b.CreateCondBr(cond, blockThen, blockElse)
|
||||||
case *ssa.Jump:
|
case *ssa.Jump:
|
||||||
blockJump := b.blockEntries[instr.Block().Succs[0]]
|
blockJump := b.blockInfo[instr.Block().Succs[0].Index].entry
|
||||||
b.CreateBr(blockJump)
|
b.CreateBr(blockJump)
|
||||||
case *ssa.MapUpdate:
|
case *ssa.MapUpdate:
|
||||||
m := b.getValue(instr.Map, getPos(instr))
|
m := b.getValue(instr.Map, getPos(instr))
|
||||||
@@ -1570,7 +1599,8 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
|
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
|
||||||
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)
|
||||||
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
|
elemLayout := b.createObjectLayout(elemType, pos)
|
||||||
|
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize, elemLayout}, "append.new")
|
||||||
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
|
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
|
||||||
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
||||||
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
||||||
@@ -1652,13 +1682,41 @@ 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")
|
||||||
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
|
// Find the minimum of the lengths.
|
||||||
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
|
minFuncName := "llvm.umin.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||||
|
minFunc := b.mod.NamedFunction(minFuncName)
|
||||||
|
if minFunc.IsNil() {
|
||||||
|
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType, b.uintptrType}, false)
|
||||||
|
minFunc = llvm.AddFunction(b.mod, minFuncName, fnType)
|
||||||
|
}
|
||||||
|
minLen := b.CreateCall(minFunc.GlobalValueType(), minFunc, []llvm.Value{dstLen, srcLen}, "copy.n")
|
||||||
|
// Multiply the length by the element size.
|
||||||
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)
|
||||||
return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
|
// NOTE: This is also NSW when uintptr is int, but we can only choose one through the C API?
|
||||||
|
size := b.CreateNUWMul(minLen, elemSize, "copy.size")
|
||||||
|
// Fetch the pointers.
|
||||||
|
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstPtr")
|
||||||
|
srcBuf := b.CreateExtractValue(src, 0, "copy.srcPtr")
|
||||||
|
// Create a memcpy.
|
||||||
|
call := b.createMemCopy("memmove", dstBuf, srcBuf, size)
|
||||||
|
align := b.targetData.ABITypeAlignment(elemType)
|
||||||
|
if align > 1 {
|
||||||
|
// Apply the type's alignment to the arguments.
|
||||||
|
// LLVM sometimes turns constant-length moves into loads and stores.
|
||||||
|
// It may use this alignment for the created loads and stores.
|
||||||
|
alignAttr := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))
|
||||||
|
call.AddCallSiteAttribute(1, alignAttr)
|
||||||
|
call.AddCallSiteAttribute(2, alignAttr)
|
||||||
|
}
|
||||||
|
// Extend and return the copied length.
|
||||||
|
if b.targetData.TypeAllocSize(minLen.Type()) < b.targetData.TypeAllocSize(b.intType) {
|
||||||
|
minLen = b.CreateZExt(minLen, b.intType, "copy.n.zext")
|
||||||
|
}
|
||||||
|
return minLen, nil
|
||||||
case "delete":
|
case "delete":
|
||||||
m := argValues[0]
|
m := argValues[0]
|
||||||
key := argValues[1]
|
key := argValues[1]
|
||||||
@@ -1686,20 +1744,66 @@ 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.
|
||||||
// We can simply reuse the existing binop comparison code, which has all
|
// Find the corresponding intrinsic name.
|
||||||
// the edge cases figured out already.
|
ty := argTypes[0].Underlying().(*types.Basic)
|
||||||
tok := token.LSS
|
llvmType := b.getLLVMType(ty)
|
||||||
if callName == "max" {
|
info := ty.Info()
|
||||||
tok = token.GTR
|
var prefix, delimeter, typeName string
|
||||||
}
|
if info&types.IsInteger != 0 {
|
||||||
result := argValues[0]
|
// This is an integer value.
|
||||||
typ := argTypes[0]
|
// Use the LLVM int min/max intrinsics.
|
||||||
for _, arg := range argValues[1:] {
|
prefix = "llvm.s"
|
||||||
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
|
if info&types.IsUnsigned != 0 {
|
||||||
if err != nil {
|
prefix = "llvm.u"
|
||||||
return result, err
|
|
||||||
}
|
}
|
||||||
result = b.CreateSelect(cmp, result, arg, "")
|
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]
|
||||||
|
for _, arg := range argValues[1:] {
|
||||||
|
result = b.CreateCall(callType, llvmFn, []llvm.Value{result, arg}, "")
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
case "panic":
|
case "panic":
|
||||||
|
|||||||
+98
-28
@@ -100,7 +100,7 @@ func (b *builder) createLandingPad() {
|
|||||||
|
|
||||||
// Continue at the 'recover' block, which returns to the parent in an
|
// Continue at the 'recover' block, which returns to the parent in an
|
||||||
// appropriate way.
|
// appropriate way.
|
||||||
b.CreateBr(b.blockEntries[b.fn.Recover])
|
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a checkpoint (similar to setjmp). This emits inline assembly that
|
// Create a checkpoint (similar to setjmp). This emits inline assembly that
|
||||||
@@ -234,41 +234,108 @@ func (b *builder) createInvokeCheckpoint() {
|
|||||||
continueBB := b.insertBasicBlock("")
|
continueBB := b.insertBasicBlock("")
|
||||||
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
||||||
b.SetInsertPointAtEnd(continueBB)
|
b.SetInsertPointAtEnd(continueBB)
|
||||||
b.blockExits[b.currentBlock] = continueBB
|
b.currentBlockInfo.exit = continueBB
|
||||||
}
|
}
|
||||||
|
|
||||||
// isInLoop checks if there is a path from a basic block to itself.
|
// isInLoop checks if there is a path from the current block to itself.
|
||||||
func isInLoop(start *ssa.BasicBlock) bool {
|
// Use Tarjan's strongly connected components algorithm to search for cycles.
|
||||||
// Use a breadth-first search to scan backwards through the block graph.
|
// A one-node SCC is a cycle iff there is an edge from the node to itself.
|
||||||
queue := []*ssa.BasicBlock{start}
|
// A multi-node SCC is always a cycle.
|
||||||
checked := map[*ssa.BasicBlock]struct{}{}
|
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||||
|
func (b *builder) isInLoop() bool {
|
||||||
|
if b.currentBlockInfo.tarjan.lowLink == 0 {
|
||||||
|
b.strongConnect(b.currentBlock)
|
||||||
|
}
|
||||||
|
return b.currentBlockInfo.tarjan.cyclic
|
||||||
|
}
|
||||||
|
|
||||||
for len(queue) > 0 {
|
func (b *builder) strongConnect(block *ssa.BasicBlock) {
|
||||||
// pop a block off of the queue
|
// Assign a new index.
|
||||||
block := queue[len(queue)-1]
|
// Indices start from 1 so that 0 can be used as a sentinel.
|
||||||
queue = queue[:len(queue)-1]
|
assignedIndex := b.tarjanIndex + 1
|
||||||
|
b.tarjanIndex = assignedIndex
|
||||||
|
|
||||||
// Search through predecessors.
|
// Apply the new index.
|
||||||
// Searching backwards means that this is pretty fast when the block is close to the start of the function.
|
blockIndex := block.Index
|
||||||
// Defers are often placed near the start of the function.
|
node := &b.blockInfo[blockIndex].tarjan
|
||||||
for _, pred := range block.Preds {
|
node.lowLink = assignedIndex
|
||||||
if pred == start {
|
|
||||||
// cycle found
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := checked[pred]; ok {
|
// Push the node onto the stack.
|
||||||
// block already checked
|
node.onStack = true
|
||||||
continue
|
b.tarjanStack = append(b.tarjanStack, uint(blockIndex))
|
||||||
}
|
|
||||||
|
|
||||||
// add to queue and checked map
|
// Process the successors.
|
||||||
queue = append(queue, pred)
|
for _, successor := range block.Succs {
|
||||||
checked[pred] = struct{}{}
|
// Look up the successor's state.
|
||||||
|
successorIndex := successor.Index
|
||||||
|
if successorIndex == blockIndex {
|
||||||
|
// Handle a self-cycle specially.
|
||||||
|
node.cyclic = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
successorNode := &b.blockInfo[successorIndex].tarjan
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case successorNode.lowLink == 0:
|
||||||
|
// This node has not yet been visisted.
|
||||||
|
b.strongConnect(successor)
|
||||||
|
|
||||||
|
case !successorNode.onStack:
|
||||||
|
// This node has been visited, but is in a different SCC.
|
||||||
|
// Ignore it, and do not update lowLink.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the lowLink index.
|
||||||
|
// This always uses the min-of-lowlink instead of using index in the on-stack case.
|
||||||
|
// This is done for two reasons:
|
||||||
|
// 1. The lowLink update can be shared between the new-node and on-stack cases.
|
||||||
|
// 2. The assigned index does not need to be saved - it is only needed for root node detection.
|
||||||
|
if successorNode.lowLink < node.lowLink {
|
||||||
|
node.lowLink = successorNode.lowLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
if node.lowLink == assignedIndex {
|
||||||
|
// This is a root node.
|
||||||
|
// Pop the SCC off the stack.
|
||||||
|
stack := b.tarjanStack
|
||||||
|
top := stack[len(stack)-1]
|
||||||
|
stack = stack[:len(stack)-1]
|
||||||
|
blocks := b.blockInfo
|
||||||
|
topNode := &blocks[top].tarjan
|
||||||
|
topNode.onStack = false
|
||||||
|
|
||||||
|
if top != uint(blockIndex) {
|
||||||
|
// The root node is not the only node in the SCC.
|
||||||
|
// Mark all nodes in this SCC as cyclic.
|
||||||
|
topNode.cyclic = true
|
||||||
|
for top != uint(blockIndex) {
|
||||||
|
top = stack[len(stack)-1]
|
||||||
|
stack = stack[:len(stack)-1]
|
||||||
|
topNode = &blocks[top].tarjan
|
||||||
|
topNode.onStack = false
|
||||||
|
topNode.cyclic = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.tarjanStack = stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tarjanNode holds per-block state for isInLoop and strongConnect.
|
||||||
|
type tarjanNode struct {
|
||||||
|
// lowLink is the index of the first visited node that is reachable from this block.
|
||||||
|
// The lowLink indices are assigned by the SCC search, and do not correspond to b.Index.
|
||||||
|
// A lowLink of 0 is used as a sentinel to mark a node which has not yet been visited.
|
||||||
|
lowLink uint
|
||||||
|
|
||||||
|
// onStack tracks whether this node is currently on the SCC search stack.
|
||||||
|
onStack bool
|
||||||
|
|
||||||
|
// cyclic indicates whether this block is in a loop.
|
||||||
|
// If lowLink is 0, strongConnect must be called before reading this field.
|
||||||
|
cyclic bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// createDefer emits a single defer instruction, to be run when this function
|
// createDefer emits a single defer instruction, to be run when this function
|
||||||
@@ -410,7 +477,10 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
|||||||
|
|
||||||
// Put this struct in an allocation.
|
// Put this struct in an allocation.
|
||||||
var alloca llvm.Value
|
var alloca llvm.Value
|
||||||
if !isInLoop(instr.Block()) {
|
if instr.Block() != b.currentBlock {
|
||||||
|
panic("block mismatch")
|
||||||
|
}
|
||||||
|
if !b.isInLoop() {
|
||||||
// This can safely use a stack allocation.
|
// This can safely use a stack allocation.
|
||||||
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
|
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
|||||||
// provided immediately. For example:
|
// provided immediately. For example:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "str {value}, {result}",
|
// "str {value}, [{result}]",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1,
|
||||||
// "result": &dest,
|
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||||
// })
|
// })
|
||||||
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
|
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||||
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
|
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
|
||||||
|
|||||||
@@ -737,7 +737,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
prevBlock := b.GetInsertBlock()
|
prevBlock := b.GetInsertBlock()
|
||||||
okBlock := b.insertBasicBlock("typeassert.ok")
|
okBlock := b.insertBasicBlock("typeassert.ok")
|
||||||
nextBlock := b.insertBasicBlock("typeassert.next")
|
nextBlock := b.insertBasicBlock("typeassert.next")
|
||||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
|
||||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||||
|
|
||||||
// Retrieve the value from the interface if the type assert was
|
// Retrieve the value from the interface if the type assert was
|
||||||
|
|||||||
+52
-8
@@ -27,6 +27,8 @@ func (b *builder) defineIntrinsicFunction() {
|
|||||||
b.createStackSaveImpl()
|
b.createStackSaveImpl()
|
||||||
case name == "runtime.KeepAlive":
|
case name == "runtime.KeepAlive":
|
||||||
b.createKeepAliveImpl()
|
b.createKeepAliveImpl()
|
||||||
|
case name == "machine.keepAliveNoEscape":
|
||||||
|
b.createMachineKeepAliveImpl()
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||||
b.createVolatileLoad()
|
b.createVolatileLoad()
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||||
@@ -48,19 +50,24 @@ 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)
|
||||||
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
params := b.fn.Params[0:3]
|
||||||
|
b.createMemCopy(
|
||||||
|
b.fn.Name(),
|
||||||
|
b.getValue(params[0], getPos(b.fn)),
|
||||||
|
b.getValue(params[1], getPos(b.fn)),
|
||||||
|
b.getValue(params[2], getPos(b.fn)),
|
||||||
|
)
|
||||||
|
b.CreateRetVoid()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) createMemCopy(kind string, dst, src, len llvm.Value) llvm.Value {
|
||||||
|
fnName := "llvm." + kind + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||||
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)
|
||||||
}
|
}
|
||||||
var params []llvm.Value
|
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{dst, src, len, llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
|
||||||
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
|
||||||
@@ -121,6 +128,43 @@ func (b *builder) createKeepAliveImpl() {
|
|||||||
b.CreateRetVoid()
|
b.CreateRetVoid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
|
||||||
|
// currently only supports pointer types.
|
||||||
|
func (b *builder) createAbiEscapeImpl() {
|
||||||
|
b.createFunctionStart(true)
|
||||||
|
|
||||||
|
// The first parameter is assumed to be a pointer. This is checked at the
|
||||||
|
// call site of createAbiEscapeImpl.
|
||||||
|
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
|
|
||||||
|
// Create an equivalent of the following C code, which is basically just a
|
||||||
|
// nop but ensures the pointerValue is kept alive:
|
||||||
|
//
|
||||||
|
// __asm__ __volatile__("" : : "r"(pointerValue))
|
||||||
|
//
|
||||||
|
// It should be portable to basically everything as the "r" register type
|
||||||
|
// exists basically everywhere.
|
||||||
|
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
|
||||||
|
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
|
||||||
|
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||||
|
|
||||||
|
b.CreateRet(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement machine.keepAliveNoEscape, which makes sure the compiler keeps the
|
||||||
|
// pointer parameter alive until this point (for GC).
|
||||||
|
func (b *builder) createMachineKeepAliveImpl() {
|
||||||
|
b.createFunctionStart(true)
|
||||||
|
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
|
|
||||||
|
// See createKeepAliveImpl for details.
|
||||||
|
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
|
||||||
|
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
|
||||||
|
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||||
|
|
||||||
|
b.CreateRetVoid()
|
||||||
|
}
|
||||||
|
|
||||||
var mathToLLVMMapping = map[string]string{
|
var mathToLLVMMapping = map[string]string{
|
||||||
"math.Ceil": "llvm.ceil.f64",
|
"math.Ceil": "llvm.ceil.f64",
|
||||||
"math.Exp": "llvm.exp.f64",
|
"math.Exp": "llvm.exp.f64",
|
||||||
|
|||||||
+90
-90
@@ -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"
|
||||||
@@ -231,6 +231,12 @@ 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()
|
||||||
@@ -248,54 +254,29 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a few checks to see whether we need to generate any object layout
|
// Create the pointer bitmap.
|
||||||
// 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)
|
||||||
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
|
||||||
if objectSizeBytes < pointerSize {
|
|
||||||
// Too small to contain a pointer.
|
|
||||||
layout := (uint64(1) << 1) | 1
|
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
|
||||||
}
|
|
||||||
bitmap := c.getPointerBitmap(t, pos)
|
|
||||||
if bitmap.BitLen() == 0 {
|
|
||||||
// There are no pointers in this type, so we can simplify the layout.
|
|
||||||
// TODO: this can be done in many other cases, e.g. when allocating an
|
|
||||||
// array (like [4][]byte, which repeats a slice 4 times).
|
|
||||||
layout := (uint64(1) << 1) | 1
|
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
|
||||||
}
|
|
||||||
if objectSizeBytes%uint64(pointerAlignment) != 0 {
|
|
||||||
// This shouldn't happen except for packed structs, which aren't
|
|
||||||
// currently used.
|
|
||||||
c.addError(pos, "internal error: unexpected object size for object with pointer field")
|
|
||||||
return llvm.ConstNull(c.dataPtrType)
|
|
||||||
}
|
|
||||||
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
|
|
||||||
|
|
||||||
pointerBits := pointerSize * 8
|
pointerBits := pointerSize * 8
|
||||||
var sizeFieldBits uint64
|
if bitmapLen < pointerBits {
|
||||||
switch pointerBits {
|
rawMask := binary.LittleEndian.Uint64(bitmap[0:8])
|
||||||
case 16:
|
layout := rawMask*pointerBits + bitmapLen
|
||||||
sizeFieldBits = 4
|
layout <<= 1
|
||||||
case 32:
|
layout |= 1
|
||||||
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
|
// Check if the layout fits.
|
||||||
// cases.
|
layout &= 1<<pointerBits - 1
|
||||||
if objectSizeWords < layoutFieldBits {
|
if (layout>>1)/pointerBits == rawMask {
|
||||||
// If it can be stored directly in the pointer value, do so.
|
// No set bits were shifted off.
|
||||||
// The runtime knows that if the least significant bit of the pointer is
|
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||||
// 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
|
||||||
@@ -303,25 +284,24 @@ 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", objectSizeWords, (objectSizeWords+15)/16, bitmap)
|
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", bitmapLen, (bitmapLen+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.
|
||||||
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
|
bitmapByteValues := make([]llvm.Value, bitmapBytes)
|
||||||
bitmap.FillBytes(bitmapBytes)
|
i8 := c.ctx.Int8Type()
|
||||||
reverseBytes(bitmapBytes) // big-endian to little-endian
|
for i, b := range bitmap {
|
||||||
var bitmapByteValues []llvm.Value
|
bitmapByteValues[i] = llvm.ConstInt(i8, uint64(b), false)
|
||||||
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, objectSizeWords, false),
|
llvm.ConstInt(c.uintptrType, bitmapLen, false),
|
||||||
llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
|
llvm.ConstArray(i8, 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)
|
||||||
@@ -329,6 +309,7 @@ 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 {
|
||||||
@@ -360,52 +341,71 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
return global
|
return global
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
// buildPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||||
// bigint at the word offset that contains a pointer. This scan is recursive.
|
// bitmap at the word offset that contains a pointer. This scan is recursive.
|
||||||
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
|
func (c *compilerContext) buildPointerBitmap(
|
||||||
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
dst []byte,
|
||||||
switch typ.TypeKind() {
|
ptrAlign uint64,
|
||||||
|
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:
|
||||||
return big.NewInt(0)
|
// These types do not contain pointers.
|
||||||
|
|
||||||
case llvm.PointerTypeKind:
|
case llvm.PointerTypeKind:
|
||||||
return big.NewInt(1)
|
// Set the corresponding position in the bitmap.
|
||||||
|
dst[offset/8] |= 1 << (offset % 8)
|
||||||
|
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
ptrs := big.NewInt(0)
|
// Recurse over struct elements.
|
||||||
for i, subtyp := range typ.StructElementTypes() {
|
for i, et := range t.StructElementTypes() {
|
||||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
eo := c.targetData.ElementOffset(t, i)
|
||||||
if subptrs.BitLen() == 0 {
|
if eo%uint64(ptrAlign) != 0 {
|
||||||
|
if typeHasPointers(et) {
|
||||||
|
// This error will let the compilation fail, but by continuing
|
||||||
|
// the error can still easily be shown.
|
||||||
|
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
offset := c.targetData.ElementOffset(typ, i)
|
c.buildPointerBitmap(
|
||||||
if offset%uint64(alignment) != 0 {
|
dst,
|
||||||
// This error will let the compilation fail, but by continuing
|
ptrAlign,
|
||||||
// the error can still easily be shown.
|
pos,
|
||||||
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
et,
|
||||||
continue
|
offset+(eo/ptrAlign),
|
||||||
}
|
)
|
||||||
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
|
|
||||||
ptrs.Or(ptrs, subptrs)
|
|
||||||
}
|
}
|
||||||
return ptrs
|
|
||||||
case llvm.ArrayTypeKind:
|
case llvm.ArrayTypeKind:
|
||||||
subtyp := typ.ElementType()
|
// Recurse over array elements.
|
||||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
len := t.ArrayLength()
|
||||||
ptrs := big.NewInt(0)
|
if len <= 0 {
|
||||||
if subptrs.BitLen() == 0 {
|
return
|
||||||
return ptrs
|
|
||||||
}
|
}
|
||||||
elementSize := c.targetData.TypeAllocSize(subtyp)
|
et := t.ElementType()
|
||||||
if elementSize%uint64(alignment) != 0 {
|
elementSize := c.targetData.TypeAllocSize(et)
|
||||||
// This error will let the compilation fail (but continues so that
|
if elementSize%ptrAlign != 0 {
|
||||||
// other errors can be shown).
|
if typeHasPointers(et) {
|
||||||
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
// This error will let the compilation fail (but continues so that
|
||||||
return ptrs
|
// other errors can be shown).
|
||||||
|
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < typ.ArrayLength(); i++ {
|
elementSize /= ptrAlign
|
||||||
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
|
for i := 0; i < len; i++ {
|
||||||
ptrs.Or(ptrs, subptrs)
|
c.buildPointerBitmap(
|
||||||
|
dst,
|
||||||
|
ptrAlign,
|
||||||
|
pos,
|
||||||
|
et,
|
||||||
|
offset+uint64(i)*elementSize,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return ptrs
|
|
||||||
default:
|
default:
|
||||||
// Should not happen.
|
// Should not happen.
|
||||||
panic("unknown LLVM type")
|
panic("unknown LLVM type")
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ func Version() int {
|
|||||||
return major
|
return major
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the byte order for the given target triple. Most targets are little
|
// ByteOrder returns the byte order for the given target triple. Most targets are little
|
||||||
// endian, but for example MIPS can be big-endian.
|
// endian, but for example MIPS can be big-endian.
|
||||||
func ByteOrder(target string) binary.ByteOrder {
|
func ByteOrder(target string) binary.ByteOrder {
|
||||||
if strings.HasPrefix(target, "mips-") {
|
if strings.HasPrefix(target, "mips-") {
|
||||||
|
|||||||
@@ -250,6 +250,9 @@ 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:
|
||||||
|
// 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
|
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
return true
|
return true
|
||||||
|
|||||||
+39
-10
@@ -142,6 +142,11 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
|||||||
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
|
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
|
||||||
llvmFn.AddAttributeAtIndex(i+1, nocapture)
|
llvmFn.AddAttributeAtIndex(i+1, nocapture)
|
||||||
}
|
}
|
||||||
|
if paramInfo.flags¶mIsReadonly != 0 && paramInfo.llvmType.TypeKind() == llvm.PointerTypeKind {
|
||||||
|
// Readonly pointer parameters (like strings) benefit from being marked as readonly.
|
||||||
|
readonly := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)
|
||||||
|
llvmFn.AddAttributeAtIndex(i+1, readonly)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a number of function or parameter attributes, depending on the
|
// Set a number of function or parameter attributes, depending on the
|
||||||
@@ -154,6 +159,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
|||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
|
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
|
||||||
case "internal/abi.NoEscape":
|
case "internal/abi.NoEscape":
|
||||||
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":
|
||||||
|
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||||
case "runtime.alloc":
|
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.
|
||||||
@@ -177,12 +184,6 @@ 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))
|
||||||
@@ -253,6 +254,23 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
|
|||||||
// The exception is the package initializer, which does appear in the
|
// The exception is the package initializer, which does appear in the
|
||||||
// *ssa.Package members and so shouldn't be created here.
|
// *ssa.Package members and so shouldn't be created here.
|
||||||
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
|
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
|
||||||
|
if origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
|
||||||
|
// This is a special implementation or internal/abi.Escape, which
|
||||||
|
// can only really be implemented in the compiler.
|
||||||
|
// For simplicity we'll only implement pointer parameters for now.
|
||||||
|
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
|
||||||
|
irbuilder := c.ctx.NewBuilder()
|
||||||
|
defer irbuilder.Dispose()
|
||||||
|
b := newBuilder(c, irbuilder, fn)
|
||||||
|
b.createAbiEscapeImpl()
|
||||||
|
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||||
|
llvmFn.SetUnnamedAddr(true)
|
||||||
|
}
|
||||||
|
// If the parameter is not of a pointer type, it will be left
|
||||||
|
// unimplemented. This will result in a linker error if the function
|
||||||
|
// is really called, making it clear it needs to be implemented.
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(fn.Blocks) == 0 {
|
if len(fn.Blocks) == 0 {
|
||||||
c.addError(fn.Pos(), "missing function body")
|
c.addError(fn.Pos(), "missing function body")
|
||||||
return
|
return
|
||||||
@@ -613,7 +631,7 @@ func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
|
|||||||
// linkName is equal to .RelString(nil) on a global and extern is false, but for
|
// linkName is equal to .RelString(nil) on a global and extern is false, but for
|
||||||
// some symbols this is different (due to //go:extern for example).
|
// some symbols this is different (due to //go:extern for example).
|
||||||
type globalInfo struct {
|
type globalInfo struct {
|
||||||
linkName string // go:extern
|
linkName string // go:extern, go:linkname
|
||||||
extern bool // go:extern
|
extern bool // go:extern
|
||||||
align int // go:align
|
align int // go:align
|
||||||
section string // go:section
|
section string // go:section
|
||||||
@@ -698,14 +716,14 @@ func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
|
|||||||
// Check for //go: pragmas, which may change the link name (among others).
|
// Check for //go: pragmas, which may change the link name (among others).
|
||||||
doc := c.astComments[info.linkName]
|
doc := c.astComments[info.linkName]
|
||||||
if doc != nil {
|
if doc != nil {
|
||||||
info.parsePragmas(doc)
|
info.parsePragmas(doc, c, g)
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse //go: pragma comments from the source. In particular, it parses the
|
// Parse //go: pragma comments from the source. In particular, it parses the
|
||||||
// //go:extern pragma on globals.
|
// //go:extern and //go:linkname pragmas on globals.
|
||||||
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext, g *ssa.Global) {
|
||||||
for _, comment := range doc.List {
|
for _, comment := range doc.List {
|
||||||
if !strings.HasPrefix(comment.Text, "//go:") {
|
if !strings.HasPrefix(comment.Text, "//go:") {
|
||||||
continue
|
continue
|
||||||
@@ -726,6 +744,17 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
|||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
info.section = parts[1]
|
info.section = parts[1]
|
||||||
}
|
}
|
||||||
|
case "//go:linkname":
|
||||||
|
if len(parts) != 3 || parts[1] != g.Name() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Only enable go:linkname when the package imports "unsafe".
|
||||||
|
// This is a slightly looser requirement than what gc uses: gc
|
||||||
|
// requires the file to import "unsafe", not the package as a
|
||||||
|
// whole.
|
||||||
|
if hasUnsafeImport(g.Pkg.Pkg) {
|
||||||
|
info.linkName = parts[2]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,14 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
return b.CreateCall(fnType, target, args, ""), nil
|
return b.CreateCall(fnType, target, args, ""), nil
|
||||||
|
|
||||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||||
|
if arch := b.archFamily(); arch != "arm" {
|
||||||
|
// Some targets pretend to be linux/arm for compatibility but aren't
|
||||||
|
// actually such a system. Make sure we emit an error instead of
|
||||||
|
// creating inline assembly that will fail to compile.
|
||||||
|
// See: https://github.com/tinygo-org/tinygo/issues/4959
|
||||||
|
return llvm.Value{}, b.makeError(call.Pos(), "system calls are not supported: target emulates a linux/arm system on "+arch)
|
||||||
|
}
|
||||||
|
|
||||||
// Implement the EABI system call convention for Linux.
|
// Implement the EABI system call convention for Linux.
|
||||||
// Source: syscall(2) man page.
|
// Source: syscall(2) man page.
|
||||||
args := []llvm.Value{}
|
args := []llvm.Value{}
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'basic.go'
|
; ModuleID = 'basic.go'
|
||||||
source_filename = "basic.go"
|
source_filename = "basic.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%main.kv = type { float, i32, i32, i32 }
|
%main.kv = type { float, i32, i32, i32 }
|
||||||
@@ -206,7 +206,7 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+7
-7
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'channel.go'
|
; ModuleID = 'channel.go'
|
||||||
source_filename = "channel.go"
|
source_filename = "channel.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime.channelOp = type { ptr, ptr, i32, ptr }
|
%runtime.channelOp = type { ptr, ptr, i32, ptr }
|
||||||
@@ -82,11 +82,11 @@ entry:
|
|||||||
store i32 1, ptr %select.send.value, align 4
|
store i32 1, ptr %select.send.value, align 4
|
||||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
||||||
store ptr %ch1, ptr %select.states.alloca, align 4
|
store ptr %ch1, ptr %select.states.alloca, align 4
|
||||||
%select.states.alloca.repack1 = getelementptr inbounds i8, ptr %select.states.alloca, i32 4
|
%select.states.alloca.repack1 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 4
|
||||||
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
|
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
|
||||||
%0 = getelementptr inbounds i8, ptr %select.states.alloca, i32 8
|
%0 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 8
|
||||||
store ptr %ch2, ptr %0, align 4
|
store ptr %ch2, ptr %0, align 4
|
||||||
%.repack3 = getelementptr inbounds i8, ptr %select.states.alloca, i32 12
|
%.repack3 = getelementptr inbounds 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) #4
|
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #4
|
||||||
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)
|
||||||
@@ -107,8 +107,8 @@ select.body: ; preds = %select.next
|
|||||||
|
|
||||||
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
|
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||||
attributes #4 = { nounwind }
|
attributes #4 = { nounwind }
|
||||||
|
|||||||
+242
-7
@@ -27,7 +27,7 @@ entry:
|
|||||||
%0 = call ptr @llvm.stacksave.p0()
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
store i32 0, ptr %defer.alloca, align 4
|
store i32 0, ptr %defer.alloca, align 4
|
||||||
%defer.alloca.repack15 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
|
%defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||||
store ptr null, ptr %defer.alloca.repack15, align 4
|
store ptr null, ptr %defer.alloca.repack15, align 4
|
||||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||||
@@ -51,7 +51,7 @@ rundefers.loophead: ; preds = %3, %rundefers.block
|
|||||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||||
|
|
||||||
rundefers.loop: ; preds = %rundefers.loophead
|
rundefers.loop: ; preds = %rundefers.loophead
|
||||||
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
|
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
|
||||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||||
store ptr %stack.next, ptr %deferPtr, align 4
|
store ptr %stack.next, ptr %deferPtr, align 4
|
||||||
%callback = load i32, ptr %2, align 4
|
%callback = load i32, ptr %2, align 4
|
||||||
@@ -87,7 +87,7 @@ rundefers.loophead6: ; preds = %5, %lpad
|
|||||||
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
|
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
|
||||||
|
|
||||||
rundefers.loop5: ; preds = %rundefers.loophead6
|
rundefers.loop5: ; preds = %rundefers.loophead6
|
||||||
%stack.next.gep8 = getelementptr inbounds i8, ptr %4, i32 4
|
%stack.next.gep8 = getelementptr inbounds nuw i8, ptr %4, i32 4
|
||||||
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4
|
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4
|
||||||
store ptr %stack.next9, ptr %deferPtr, align 4
|
store ptr %stack.next9, ptr %deferPtr, align 4
|
||||||
%callback11 = load i32, ptr %4, align 4
|
%callback11 = load i32, ptr %4, align 4
|
||||||
@@ -144,11 +144,11 @@ entry:
|
|||||||
%0 = call ptr @llvm.stacksave.p0()
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
store i32 0, ptr %defer.alloca, align 4
|
store i32 0, ptr %defer.alloca, align 4
|
||||||
%defer.alloca.repack22 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
|
%defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||||
store ptr null, ptr %defer.alloca.repack22, align 4
|
store ptr null, ptr %defer.alloca.repack22, align 4
|
||||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||||
store i32 1, ptr %defer.alloca2, align 4
|
store i32 1, ptr %defer.alloca2, align 4
|
||||||
%defer.alloca2.repack23 = getelementptr inbounds i8, ptr %defer.alloca2, i32 4
|
%defer.alloca2.repack23 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
|
||||||
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
|
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
|
||||||
store ptr %defer.alloca2, ptr %deferPtr, align 4
|
store ptr %defer.alloca2, ptr %deferPtr, align 4
|
||||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||||
@@ -172,7 +172,7 @@ rundefers.loophead: ; preds = %4, %3, %rundefers.b
|
|||||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||||
|
|
||||||
rundefers.loop: ; preds = %rundefers.loophead
|
rundefers.loop: ; preds = %rundefers.loophead
|
||||||
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
|
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
|
||||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||||
store ptr %stack.next, ptr %deferPtr, align 4
|
store ptr %stack.next, ptr %deferPtr, align 4
|
||||||
%callback = load i32, ptr %2, align 4
|
%callback = load i32, ptr %2, align 4
|
||||||
@@ -218,7 +218,7 @@ rundefers.loophead10: ; preds = %7, %6, %lpad
|
|||||||
br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9
|
br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9
|
||||||
|
|
||||||
rundefers.loop9: ; preds = %rundefers.loophead10
|
rundefers.loop9: ; preds = %rundefers.loophead10
|
||||||
%stack.next.gep12 = getelementptr inbounds i8, ptr %5, i32 4
|
%stack.next.gep12 = getelementptr inbounds nuw i8, ptr %5, i32 4
|
||||||
%stack.next13 = load ptr, ptr %stack.next.gep12, align 4
|
%stack.next13 = load ptr, ptr %stack.next.gep12, align 4
|
||||||
store ptr %stack.next13, ptr %deferPtr, align 4
|
store ptr %stack.next13, ptr %deferPtr, align 4
|
||||||
%callback15 = load i32, ptr %5, align 4
|
%callback15 = load i32, ptr %5, align 4
|
||||||
@@ -270,6 +270,241 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%deferPtr = alloca ptr, align 4
|
||||||
|
store ptr null, ptr %deferPtr, align 4
|
||||||
|
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||||
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
for.body: ; preds = %for.body, %entry
|
||||||
|
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||||
|
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
|
||||||
|
store i32 0, ptr %defer.alloc.call, align 4
|
||||||
|
%defer.alloc.call.repack1 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
|
||||||
|
store ptr %defer.next, ptr %defer.alloc.call.repack1, align 4
|
||||||
|
%defer.alloc.call.repack3 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
|
||||||
|
store i32 8, ptr %defer.alloc.call.repack3, align 4
|
||||||
|
store ptr %defer.alloc.call, ptr %deferPtr, align 4
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
recover: ; preds = %rundefers.end
|
||||||
|
ret void
|
||||||
|
|
||||||
|
lpad: ; No predecessors!
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.loophead: ; preds = %rundefers.callback0, %lpad
|
||||||
|
br i1 poison, label %rundefers.end, label %rundefers.loop
|
||||||
|
|
||||||
|
rundefers.loop: ; preds = %rundefers.loophead
|
||||||
|
switch i32 poison, label %rundefers.default [
|
||||||
|
i32 0, label %rundefers.callback0
|
||||||
|
]
|
||||||
|
|
||||||
|
rundefers.callback0: ; preds = %rundefers.loop
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.default: ; preds = %rundefers.loop
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
rundefers.end: ; preds = %rundefers.loophead
|
||||||
|
br label %recover
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.deferLoop(ptr %context) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%deferPtr = alloca ptr, align 4
|
||||||
|
store ptr null, ptr %deferPtr, align 4
|
||||||
|
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||||
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
|
br label %for.loop
|
||||||
|
|
||||||
|
for.loop: ; preds = %for.body, %entry
|
||||||
|
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
|
||||||
|
%2 = icmp slt i32 %1, 10
|
||||||
|
br i1 %2, label %for.body, label %for.done
|
||||||
|
|
||||||
|
for.body: ; preds = %for.loop
|
||||||
|
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||||
|
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
|
||||||
|
store i32 0, ptr %defer.alloc.call, align 4
|
||||||
|
%defer.alloc.call.repack13 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
|
||||||
|
store ptr %defer.next, ptr %defer.alloc.call.repack13, align 4
|
||||||
|
%defer.alloc.call.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
|
||||||
|
store i32 %1, ptr %defer.alloc.call.repack15, align 4
|
||||||
|
store ptr %defer.alloc.call, ptr %deferPtr, align 4
|
||||||
|
%3 = add i32 %1, 1
|
||||||
|
br label %for.loop
|
||||||
|
|
||||||
|
for.done: ; preds = %for.loop
|
||||||
|
br label %rundefers.block
|
||||||
|
|
||||||
|
rundefers.after: ; preds = %rundefers.end
|
||||||
|
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||||
|
ret void
|
||||||
|
|
||||||
|
rundefers.block: ; preds = %for.done
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
|
||||||
|
%4 = load ptr, ptr %deferPtr, align 4
|
||||||
|
%stackIsNil = icmp eq ptr %4, null
|
||||||
|
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||||
|
|
||||||
|
rundefers.loop: ; preds = %rundefers.loophead
|
||||||
|
%stack.next.gep = getelementptr inbounds nuw i8, ptr %4, i32 4
|
||||||
|
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||||
|
store ptr %stack.next, ptr %deferPtr, align 4
|
||||||
|
%callback = load i32, ptr %4, align 4
|
||||||
|
switch i32 %callback, label %rundefers.default [
|
||||||
|
i32 0, label %rundefers.callback0
|
||||||
|
]
|
||||||
|
|
||||||
|
rundefers.callback0: ; preds = %rundefers.loop
|
||||||
|
%gep = getelementptr inbounds nuw i8, ptr %4, i32 8
|
||||||
|
%param = load i32, ptr %gep, align 4
|
||||||
|
call void @runtime.printlock(ptr undef) #4
|
||||||
|
call void @runtime.printint32(i32 %param, ptr undef) #4
|
||||||
|
call void @runtime.printunlock(ptr undef) #4
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.default: ; preds = %rundefers.loop
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
rundefers.end: ; preds = %rundefers.loophead
|
||||||
|
br label %rundefers.after
|
||||||
|
|
||||||
|
recover: ; preds = %rundefers.end1
|
||||||
|
ret void
|
||||||
|
|
||||||
|
lpad: ; No predecessors!
|
||||||
|
br label %rundefers.loophead4
|
||||||
|
|
||||||
|
rundefers.loophead4: ; preds = %rundefers.callback010, %lpad
|
||||||
|
br i1 poison, label %rundefers.end1, label %rundefers.loop3
|
||||||
|
|
||||||
|
rundefers.loop3: ; preds = %rundefers.loophead4
|
||||||
|
switch i32 poison, label %rundefers.default2 [
|
||||||
|
i32 0, label %rundefers.callback010
|
||||||
|
]
|
||||||
|
|
||||||
|
rundefers.callback010: ; preds = %rundefers.loop3
|
||||||
|
br label %rundefers.loophead4
|
||||||
|
|
||||||
|
rundefers.default2: ; preds = %rundefers.loop3
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
rundefers.end1: ; preds = %rundefers.loophead4
|
||||||
|
br label %recover
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%defer.alloca = alloca { i32, ptr, i32 }, align 4
|
||||||
|
%deferPtr = alloca ptr, align 4
|
||||||
|
store ptr null, ptr %deferPtr, align 4
|
||||||
|
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||||
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
|
br label %for.loop
|
||||||
|
|
||||||
|
for.loop: ; preds = %for.body, %entry
|
||||||
|
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
|
||||||
|
%2 = icmp slt i32 %1, 10
|
||||||
|
br i1 %2, label %for.body, label %for.done
|
||||||
|
|
||||||
|
for.body: ; preds = %for.loop
|
||||||
|
%3 = add i32 %1, 1
|
||||||
|
br label %for.loop
|
||||||
|
|
||||||
|
for.done: ; preds = %for.loop
|
||||||
|
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||||
|
store i32 0, ptr %defer.alloca, align 4
|
||||||
|
%defer.alloca.repack16 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||||
|
store ptr %defer.next, ptr %defer.alloca.repack16, align 4
|
||||||
|
%defer.alloca.repack18 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 8
|
||||||
|
store i32 1, ptr %defer.alloca.repack18, align 4
|
||||||
|
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||||
|
br label %for.loop1
|
||||||
|
|
||||||
|
for.loop1: ; preds = %for.body2, %for.done
|
||||||
|
%4 = phi i32 [ 0, %for.done ], [ %6, %for.body2 ]
|
||||||
|
%5 = icmp slt i32 %4, 10
|
||||||
|
br i1 %5, label %for.body2, label %for.done3
|
||||||
|
|
||||||
|
for.body2: ; preds = %for.loop1
|
||||||
|
%6 = add i32 %4, 1
|
||||||
|
br label %for.loop1
|
||||||
|
|
||||||
|
for.done3: ; preds = %for.loop1
|
||||||
|
br label %rundefers.block
|
||||||
|
|
||||||
|
rundefers.after: ; preds = %rundefers.end
|
||||||
|
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||||
|
ret void
|
||||||
|
|
||||||
|
rundefers.block: ; preds = %for.done3
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
|
||||||
|
%7 = load ptr, ptr %deferPtr, align 4
|
||||||
|
%stackIsNil = icmp eq ptr %7, null
|
||||||
|
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||||
|
|
||||||
|
rundefers.loop: ; preds = %rundefers.loophead
|
||||||
|
%stack.next.gep = getelementptr inbounds nuw i8, ptr %7, i32 4
|
||||||
|
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||||
|
store ptr %stack.next, ptr %deferPtr, align 4
|
||||||
|
%callback = load i32, ptr %7, align 4
|
||||||
|
switch i32 %callback, label %rundefers.default [
|
||||||
|
i32 0, label %rundefers.callback0
|
||||||
|
]
|
||||||
|
|
||||||
|
rundefers.callback0: ; preds = %rundefers.loop
|
||||||
|
%gep = getelementptr inbounds nuw i8, ptr %7, i32 8
|
||||||
|
%param = load i32, ptr %gep, align 4
|
||||||
|
call void @runtime.printlock(ptr undef) #4
|
||||||
|
call void @runtime.printint32(i32 %param, ptr undef) #4
|
||||||
|
call void @runtime.printunlock(ptr undef) #4
|
||||||
|
br label %rundefers.loophead
|
||||||
|
|
||||||
|
rundefers.default: ; preds = %rundefers.loop
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
rundefers.end: ; preds = %rundefers.loophead
|
||||||
|
br label %rundefers.after
|
||||||
|
|
||||||
|
recover: ; preds = %rundefers.end4
|
||||||
|
ret void
|
||||||
|
|
||||||
|
lpad: ; No predecessors!
|
||||||
|
br label %rundefers.loophead7
|
||||||
|
|
||||||
|
rundefers.loophead7: ; preds = %rundefers.callback013, %lpad
|
||||||
|
br i1 poison, label %rundefers.end4, label %rundefers.loop6
|
||||||
|
|
||||||
|
rundefers.loop6: ; preds = %rundefers.loophead7
|
||||||
|
switch i32 poison, label %rundefers.default5 [
|
||||||
|
i32 0, label %rundefers.callback013
|
||||||
|
]
|
||||||
|
|
||||||
|
rundefers.callback013: ; preds = %rundefers.loop6
|
||||||
|
br label %rundefers.loophead7
|
||||||
|
|
||||||
|
rundefers.default5: ; preds = %rundefers.loop6
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
rundefers.end4: ; preds = %rundefers.loophead7
|
||||||
|
br label %recover
|
||||||
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||||
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
attributes #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" }
|
||||||
|
|||||||
Vendored
+20
@@ -18,3 +18,23 @@ func deferMultiple() {
|
|||||||
}()
|
}()
|
||||||
external()
|
external()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deferInfiniteLoop() {
|
||||||
|
for {
|
||||||
|
defer print(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deferLoop() {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
defer print(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deferBetweenLoops() {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
}
|
||||||
|
defer print(1)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'float.go'
|
; ModuleID = 'float.go'
|
||||||
source_filename = "float.go"
|
source_filename = "float.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||||
@@ -93,6 +93,6 @@ entry:
|
|||||||
ret i8 %0
|
ret i8 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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" }
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'func.go'
|
; ModuleID = 'func.go'
|
||||||
source_filename = "func.go"
|
source_filename = "func.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||||
@@ -44,7 +44,7 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+8
@@ -24,6 +24,10 @@ 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
|
||||||
@@ -58,6 +62,10 @@ 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() {
|
||||||
|
|||||||
Vendored
+19
-15
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'gc.go'
|
; ModuleID = 'gc.go'
|
||||||
source_filename = "gc.go"
|
source_filename = "gc.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._interface = type { ptr, ptr }
|
%runtime._interface = type { ptr, ptr }
|
||||||
@@ -16,11 +16,12 @@ 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-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-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-0001" = 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-0100000000000000" = 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
|
||||||
|
|
||||||
@@ -80,12 +81,15 @@ 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-2000000000000001", ptr undef) #3
|
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000020", 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-0001", ptr undef) #3
|
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000000", 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,18 +109,18 @@ entry:
|
|||||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice, ptr @main.slice1, align 4
|
store ptr %makeslice, ptr @main.slice1, align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 4), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 4), align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 8), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 8), align 4
|
||||||
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice1, ptr @main.slice2, align 4
|
store ptr %makeslice1, ptr @main.slice2, align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 4), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 4), align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 8), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 8), align 4
|
||||||
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice3, ptr @main.slice3, align 4
|
store ptr %makeslice3, ptr @main.slice3, align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 4), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 4), align 4
|
||||||
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 8), align 4
|
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 8), align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +131,7 @@ entry:
|
|||||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store double %v.r, ptr %0, align 8
|
store double %v.r, ptr %0, align 8
|
||||||
%.repack1 = getelementptr inbounds i8, ptr %0, i32 8
|
%.repack1 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
store double %v.i, ptr %.repack1, align 8
|
store double %v.i, ptr %.repack1, align 8
|
||||||
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
|
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
|
||||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
|
||||||
@@ -135,7 +139,7 @@ entry:
|
|||||||
ret %runtime._interface %1
|
ret %runtime._interface %1
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'go1.20.go'
|
; ModuleID = 'go1.20.go'
|
||||||
source_filename = "go1.20.go"
|
source_filename = "go1.20.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._string = type { ptr, i32 }
|
%runtime._string = type { ptr, i32 }
|
||||||
@@ -50,14 +50,14 @@ unsafe.String.throw: ; preds = %entry
|
|||||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
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) #3
|
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
ret ptr %s.data
|
ret ptr %s.data
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+42
-36
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'go1.21.go'
|
; ModuleID = 'go1.21.go'
|
||||||
source_filename = "go1.21.go"
|
source_filename = "go1.21.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._string = type { ptr, i32 }
|
%runtime._string = type { ptr, i32 }
|
||||||
@@ -22,6 +22,9 @@ entry:
|
|||||||
ret i32 %a
|
ret i32 %a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.smin.i32(i32, i32) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
@@ -53,6 +56,9 @@ entry:
|
|||||||
ret i8 %0
|
ret i8 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i8 @llvm.umin.i8(i8, i8) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
@@ -60,24 +66,31 @@ entry:
|
|||||||
ret i32 %0
|
ret i32 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.umin.i32(i32, i32) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp olt float %a, %b
|
%0 = call float @llvm.minimum.f32(float %a, float %b)
|
||||||
%1 = select i1 %0, float %a, float %b
|
ret float %0
|
||||||
ret float %1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare float @llvm.minimum.f32(float, float) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp olt double %a, %b
|
%0 = call double @llvm.minimum.f64(double %a, double %b)
|
||||||
%1 = select i1 %0, double %a, double %b
|
ret double %0
|
||||||
ret double %1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare double @llvm.minimum.f64(double, double) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
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
|
||||||
@@ -86,12 +99,12 @@ entry:
|
|||||||
%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) #5
|
%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 = extractvalue %runtime._string %5, 0
|
%6 = select i1 %4, ptr %a.data, ptr %b.data
|
||||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
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, i32, ptr, i32, ptr) #1
|
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 #2 {
|
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
@@ -100,6 +113,9 @@ entry:
|
|||||||
ret i32 %0
|
ret i32 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.smax.i32(i32, i32) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
@@ -107,16 +123,21 @@ entry:
|
|||||||
ret i32 %0
|
ret i32 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.umax.i32(i32, i32) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp ogt float %a, %b
|
%0 = call float @llvm.maximum.f32(float %a, float %b)
|
||||||
%1 = select i1 %0, float %a, float %b
|
ret float %0
|
||||||
ret float %1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare float @llvm.maximum.f32(float, float) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
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
|
||||||
@@ -125,7 +146,7 @@ entry:
|
|||||||
%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) #5
|
%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 = extractvalue %runtime._string %5, 0
|
%6 = select i1 %4, ptr %a.data, ptr %b.data
|
||||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret %runtime._string %5
|
ret %runtime._string %5
|
||||||
}
|
}
|
||||||
@@ -139,7 +160,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
|
||||||
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) #4
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||||
@@ -156,24 +177,9 @@ entry:
|
|||||||
|
|
||||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
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" }
|
||||||
declare i32 @llvm.smin.i32(i32, i32) #4
|
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" }
|
||||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||||
declare i8 @llvm.umin.i8(i8, i8) #4
|
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
|
||||||
declare i32 @llvm.umin.i32(i32, i32) #4
|
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
|
||||||
declare i32 @llvm.smax.i32(i32, i32) #4
|
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
|
||||||
declare i32 @llvm.umax.i32(i32, i32) #4
|
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
|
||||||
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
|
||||||
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
|
||||||
attributes #5 = { nounwind }
|
attributes #5 = { nounwind }
|
||||||
|
|||||||
+47
-40
@@ -17,8 +17,8 @@ entry:
|
|||||||
; 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 #1 {
|
||||||
entry:
|
entry:
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #9
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #11
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ declare void @main.regularFunction(i32, ptr) #2
|
|||||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
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) #9
|
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +39,8 @@ 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 #1 {
|
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) #9
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,18 +61,18 @@ entry:
|
|||||||
; 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 #1 {
|
||||||
entry:
|
entry:
|
||||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
|
||||||
store i32 3, ptr %n, align 4
|
store i32 3, ptr %n, align 4
|
||||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
|
||||||
store i32 5, ptr %0, align 4
|
store i32 5, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds 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) #9
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
|
||||||
%2 = load i32, ptr %n, align 4
|
%2 = load i32, ptr %n, align 4
|
||||||
call void @runtime.printlock(ptr undef) #9
|
call void @runtime.printlock(ptr undef) #11
|
||||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
call void @runtime.printint32(i32 %2, ptr undef) #11
|
||||||
call void @runtime.printunlock(ptr undef) #9
|
call void @runtime.printunlock(ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ entry:
|
|||||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load i32, ptr %0, align 4
|
%1 = load i32, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds 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)
|
||||||
ret void
|
ret void
|
||||||
@@ -102,14 +102,14 @@ declare void @runtime.printunlock(ptr) #2
|
|||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
|
||||||
store i32 5, ptr %0, align 4
|
store i32 5, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds 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 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) #9
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #11
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,11 +117,11 @@ entry:
|
|||||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load i32, ptr %0, align 4
|
%1 = load i32, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
%3 = load ptr, ptr %2, align 4
|
%3 = load ptr, ptr %2, align 4
|
||||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
%4 = getelementptr inbounds 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) #9
|
call void %5(i32 %1, ptr %3) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,16 +134,21 @@ entry:
|
|||||||
; 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 #1 {
|
||||||
entry:
|
entry:
|
||||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||||
|
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.umin.i32(i32, i32) #7
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||||
|
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
|
||||||
|
|
||||||
; 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 #1 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
call void @runtime.chanClose(ptr %ch, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,32 +157,32 @@ 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 #1 {
|
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
|
||||||
store ptr %itf.value, ptr %0, align 4
|
store ptr %itf.value, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
store ptr @"main$string", ptr %1, align 4
|
store ptr @"main$string", ptr %1, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 8
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
store i32 4, ptr %2, align 4
|
store i32 4, ptr %2, align 4
|
||||||
%3 = getelementptr inbounds i8, ptr %0, i32 12
|
%3 = getelementptr inbounds 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) #9
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #11
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load ptr, ptr %0, align 4
|
%1 = load ptr, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
%3 = load ptr, ptr %2, align 4
|
%3 = load ptr, ptr %2, align 4
|
||||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
%5 = load i32, ptr %4, align 4
|
%5 = load i32, ptr %4, align 4
|
||||||
%6 = getelementptr inbounds i8, ptr %0, i32 12
|
%6 = getelementptr inbounds 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) #9
|
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +193,8 @@ attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb
|
|||||||
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||||
attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||||
attributes #9 = { nounwind }
|
attributes #9 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||||
|
attributes #10 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||||
|
attributes #11 = { nounwind }
|
||||||
|
|||||||
+61
-54
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'goroutine.go'
|
; ModuleID = 'goroutine.go'
|
||||||
source_filename = "goroutine.go"
|
source_filename = "goroutine.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
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
|
||||||
@@ -19,7 +19,7 @@ entry:
|
|||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
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) #9
|
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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@ declare void @runtime.deadlock(ptr) #1
|
|||||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
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) #9
|
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
|
||||||
call void @runtime.deadlock(ptr undef) #9
|
call void @runtime.deadlock(ptr undef) #11
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ 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 #2 {
|
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) #9
|
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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unn
|
|||||||
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) #9
|
call void @runtime.deadlock(ptr undef) #11
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,21 +64,21 @@ entry:
|
|||||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
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) #9
|
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
|
||||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
|
||||||
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) #9
|
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
|
||||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
|
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #11
|
||||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
|
||||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||||
store i32 5, ptr %0, align 4
|
store i32 5, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds 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) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||||
%2 = load i32, ptr %n, align 4
|
%2 = load i32, ptr %n, align 4
|
||||||
call void @runtime.printlock(ptr undef) #9
|
call void @runtime.printlock(ptr undef) #11
|
||||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
call void @runtime.printint32(i32 %2, ptr undef) #11
|
||||||
call void @runtime.printunlock(ptr undef) #9
|
call void @runtime.printunlock(ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,10 +93,10 @@ entry:
|
|||||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load i32, ptr %0, align 4
|
%1 = load i32, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds 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) #9
|
call void @runtime.deadlock(ptr undef) #11
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,14 +110,14 @@ declare void @runtime.printunlock(ptr) #1
|
|||||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%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) #9
|
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
|
||||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||||
store i32 5, ptr %0, align 4
|
store i32 5, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds 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 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) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,12 +125,12 @@ entry:
|
|||||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load i32, ptr %0, align 4
|
%1 = load i32, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
%3 = load ptr, ptr %2, align 4
|
%3 = load ptr, ptr %2, align 4
|
||||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
%4 = getelementptr inbounds 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) #9
|
call void %5(i32 %1, ptr %3) #11
|
||||||
call void @runtime.deadlock(ptr undef) #9
|
call void @runtime.deadlock(ptr undef) #11
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,16 +143,21 @@ entry:
|
|||||||
; 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 #2 {
|
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 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||||
|
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.umin.i32(i32, i32) #7
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||||
|
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
call void @runtime.chanClose(ptr %ch, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,43 +167,45 @@ declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
|
|||||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||||
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) #9
|
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
|
||||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||||
store ptr %itf.value, ptr %0, align 4
|
store ptr %itf.value, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
store ptr @"main$string", ptr %1, align 4
|
store ptr @"main$string", ptr %1, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 8
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
store i32 4, ptr %2, align 4
|
store i32 4, ptr %2, align 4
|
||||||
%3 = getelementptr inbounds i8, ptr %0, i32 12
|
%3 = getelementptr inbounds 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) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
|
||||||
entry:
|
entry:
|
||||||
%1 = load ptr, ptr %0, align 4
|
%1 = load ptr, ptr %0, align 4
|
||||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
%3 = load ptr, ptr %2, align 4
|
%3 = load ptr, ptr %2, align 4
|
||||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
%5 = load i32, ptr %4, align 4
|
%5 = load i32, ptr %4, align 4
|
||||||
%6 = getelementptr inbounds i8, ptr %0, i32 12
|
%6 = getelementptr inbounds 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) #9
|
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #11
|
||||||
call void @runtime.deadlock(ptr undef) #9
|
call void @runtime.deadlock(ptr undef) #11
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
|
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
|
||||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
attributes #4 = { nounwind "target-features"="+bulk-memory,+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,+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,+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 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||||
attributes #9 = { nounwind }
|
attributes #9 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||||
|
attributes #10 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||||
|
attributes #11 = { nounwind }
|
||||||
|
|||||||
Vendored
+8
-8
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'interface.go'
|
; ModuleID = 'interface.go'
|
||||||
source_filename = "interface.go"
|
source_filename = "interface.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._interface = type { ptr, ptr }
|
%runtime._interface = type { ptr, ptr }
|
||||||
@@ -130,11 +130,11 @@ entry:
|
|||||||
|
|
||||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
|
attributes #3 = { "target-features"="+bulk-memory,+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,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
||||||
attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
attributes #5 = { "target-features"="+bulk-memory,+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 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
attributes #6 = { "target-features"="+bulk-memory,+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 }
|
attributes #7 = { nounwind }
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'pointer.go'
|
; ModuleID = 'pointer.go'
|
||||||
source_filename = "pointer.go"
|
source_filename = "pointer.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||||
@@ -44,7 +44,7 @@ entry:
|
|||||||
ret ptr %x
|
ret ptr %x
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+11
-11
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'pragma.go'
|
; ModuleID = 'pragma.go'
|
||||||
source_filename = "pragma.go"
|
source_filename = "pragma.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
@extern_global = external global [0 x i8], align 1
|
@extern_global = external global [0 x i8], align 1
|
||||||
@@ -93,13 +93,13 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
|
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" }
|
||||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #4 = { inlinehint 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,+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" }
|
||||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
|
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,+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"="modulename" "wasm-import-name"="import1" }
|
||||||
attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
attributes #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" }
|
||||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
|
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" }
|
||||||
|
|||||||
Vendored
+50
-42
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'slice.go'
|
; ModuleID = 'slice.go'
|
||||||
source_filename = "slice.go"
|
source_filename = "slice.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||||
@@ -38,7 +38,7 @@ lookup.next: ; preds = %entry
|
|||||||
ret i32 %1
|
ret i32 %1
|
||||||
|
|
||||||
lookup.throw: ; preds = %entry
|
lookup.throw: ; preds = %entry
|
||||||
call void @runtime.lookupPanic(ptr undef) #3
|
call void @runtime.lookupPanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,49 +48,55 @@ declare void @runtime.lookupPanic(ptr) #1
|
|||||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
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) #3
|
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
store i32 1, ptr %varargs, align 4
|
store i32 1, ptr %varargs, align 4
|
||||||
%0 = getelementptr inbounds i8, ptr %varargs, i32 4
|
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4
|
||||||
store i32 2, ptr %0, align 4
|
store i32 2, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds i8, ptr %varargs, i32 8
|
%1 = getelementptr inbounds 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 undef) #3
|
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
%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) #3
|
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret { ptr, i32, i32 } %4
|
ret { ptr, i32, i32 } %4
|
||||||
}
|
}
|
||||||
|
|
||||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
|
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #1
|
||||||
|
|
||||||
; 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 #2 {
|
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 undef) #3
|
%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.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) #3
|
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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 #2 {
|
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 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
|
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||||
|
%copy.size = shl nuw i32 %copy.n, 2
|
||||||
|
call void @llvm.memmove.p0.p0.i32(ptr align 4 %dst.data, ptr align 4 %src.data, i32 %copy.size, i1 false)
|
||||||
ret i32 %copy.n
|
ret i32 %copy.n
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||||
|
declare i32 @llvm.umin.i32(i32, i32) #3
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||||
|
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #4
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
|
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||||
@@ -100,15 +106,15 @@ entry:
|
|||||||
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) #3
|
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
%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) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret { ptr, i32, i32 } %2
|
ret { ptr, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
slice.throw: ; preds = %entry
|
||||||
call void @runtime.slicePanic(ptr undef) #3
|
call void @runtime.slicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,15 +129,15 @@ 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) #3
|
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
%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) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret { ptr, i32, i32 } %2
|
ret { ptr, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
slice.throw: ; preds = %entry
|
||||||
call void @runtime.slicePanic(ptr undef) #3
|
call void @runtime.slicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,15 +150,15 @@ 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) #3
|
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
%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) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret { ptr, i32, i32 } %2
|
ret { ptr, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
slice.throw: ; preds = %entry
|
||||||
call void @runtime.slicePanic(ptr undef) #3
|
call void @runtime.slicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,15 +171,15 @@ 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) #3
|
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
%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) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret { ptr, i32, i32 } %2
|
ret { ptr, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
slice.throw: ; preds = %entry
|
||||||
call void @runtime.slicePanic(ptr undef) #3
|
call void @runtime.slicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +188,7 @@ 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) #3
|
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret ptr %0
|
ret ptr %0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +198,7 @@ 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) #3
|
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
ret ptr %1
|
ret ptr %1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +212,7 @@ 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) #3
|
call void @runtime.sliceToArrayPointerPanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +222,8 @@ declare void @runtime.sliceToArrayPointerPanic(ptr) #1
|
|||||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
|
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) #3
|
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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
|
||||||
@@ -242,11 +248,11 @@ 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) #3
|
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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) #3
|
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,11 +272,11 @@ 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) #3
|
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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) #3
|
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,11 +296,11 @@ 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) #3
|
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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) #3
|
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,15 +320,17 @@ 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) #3
|
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
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) #3
|
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||||
|
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||||
|
attributes #5 = { nounwind }
|
||||||
|
|||||||
Vendored
+14
-14
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'string.go'
|
; ModuleID = 'string.go'
|
||||||
source_filename = "string.go"
|
source_filename = "string.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._string = type { ptr, i32 }
|
%runtime._string = type { ptr, i32 }
|
||||||
@@ -31,13 +31,13 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
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 %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
|
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
|
||||||
@@ -55,16 +55,16 @@ lookup.throw: ; preds = %entry
|
|||||||
declare void @runtime.lookupPanic(ptr) #1
|
declare void @runtime.lookupPanic(ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
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) #3
|
%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, i32, ptr, i32, ptr) #1
|
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
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) #3
|
%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
|
||||||
@@ -72,23 +72,23 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
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) #3
|
%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, i32, ptr, i32, ptr) #1
|
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
|
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 ult i32 %0, %s.len
|
%.not = icmp ugt i32 %s.len, %0
|
||||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||||
|
|
||||||
lookup.next: ; preds = %entry
|
lookup.next: ; preds = %entry
|
||||||
%1 = getelementptr inbounds i8, ptr %s.data, i32 %0
|
%1 = getelementptr inbounds nuw i8, ptr %s.data, i32 %0
|
||||||
%2 = load i8, ptr %1, align 1
|
%2 = load i8, ptr %1, align 1
|
||||||
ret i8 %2
|
ret i8 %2
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ lookup.throw: ; preds = %entry
|
|||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 }
|
||||||
|
|||||||
Vendored
+19
-19
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'zeromap.go'
|
; ModuleID = 'zeromap.go'
|
||||||
source_filename = "zeromap.go"
|
source_filename = "zeromap.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%main.hasPadding = type { i1, i32, i1 }
|
%main.hasPadding = type { i1, i32, i1 }
|
||||||
@@ -27,9 +27,9 @@ 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 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%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.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
|
%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)
|
||||||
@@ -60,9 +60,9 @@ 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
|
||||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%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.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 @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)
|
||||||
@@ -81,16 +81,16 @@ entry:
|
|||||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||||
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
|
%hashmap.key.repack1 = getelementptr inbounds 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 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||||
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||||
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
|
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
|
||||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
|
%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.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
|
%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)
|
||||||
@@ -109,16 +109,16 @@ entry:
|
|||||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||||
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
|
%hashmap.key.repack1 = getelementptr inbounds 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 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||||
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||||
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
|
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
|
||||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
|
%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.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 @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)
|
||||||
@@ -132,9 +132,9 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
attributes #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,+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 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
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 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||||
attributes #5 = { nounwind }
|
attributes #5 = { nounwind }
|
||||||
|
|||||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747953325,
|
"lastModified": 1770136044,
|
||||||
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
|
"narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
|
"rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "nixos-25.05",
|
"ref": "nixos-25.11",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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.05";
|
nixpkgs.url = "nixpkgs/nixos-25.11";
|
||||||
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,8 +5,6 @@ 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/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
|
||||||
github.com/chromedp/chromedp v0.7.6
|
|
||||||
github.com/gofrs/flock v0.8.1
|
github.com/gofrs/flock v0.8.1
|
||||||
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
|
||||||
@@ -24,13 +22,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
|
||||||
github.com/creack/goselect v0.1.2 // indirect
|
github.com/creack/goselect v0.1.2 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
|
||||||
github.com/gobwas/ws v1.1.0 // indirect
|
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
|
|||||||
@@ -2,33 +2,16 @@ github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3k
|
|||||||
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/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
|
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
|
||||||
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
|
|
||||||
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
|
|
||||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
|
||||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
|
||||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
github.com/creack/goselect v0.1.2 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.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/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
|
||||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
|
||||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
|
||||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
github.com/gofrs/flock v0.8.1 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/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/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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
|
||||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 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,8 +25,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
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-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/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
|
||||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 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/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||||
@@ -63,8 +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-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.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=
|
||||||
|
|||||||
+1
-1
@@ -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.38.0"
|
const version = "0.41.0-dev"
|
||||||
|
|
||||||
// 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).
|
||||||
|
|||||||
+2
-11
@@ -2,7 +2,6 @@ package interp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -11,25 +10,17 @@ 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)
|
||||||
|
|||||||
+23
-52
@@ -312,33 +312,28 @@ 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 callFn.name == "runtime.sliceCopy":
|
case strings.HasPrefix(callFn.name, "llvm.umin."):
|
||||||
// sliceCopy implements the built-in copy function for slices.
|
locals[inst.localIndex] = makeLiteralInt(min(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth())
|
||||||
// It is implemented here so that it can be used even if the
|
case strings.HasPrefix(callFn.name, "llvm.smin."):
|
||||||
// runtime implementation is not available. Doing it this way
|
locals[inst.localIndex] = makeLiteralInt(uint64(min(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth())
|
||||||
// may also be faster.
|
case strings.HasPrefix(callFn.name, "llvm.umax."):
|
||||||
// Code:
|
locals[inst.localIndex] = makeLiteralInt(max(operands[1].Uint(r), operands[2].Uint(r)), inst.llvmInst.Type().IntTypeWidth())
|
||||||
// func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int {
|
case strings.HasPrefix(callFn.name, "llvm.smax."):
|
||||||
// n := srcLen
|
locals[inst.localIndex] = makeLiteralInt(uint64(max(operands[1].Int(r), operands[2].Int(r))), inst.llvmInst.Type().IntTypeWidth())
|
||||||
// if n > dstLen {
|
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
|
||||||
// n = dstLen
|
// Copy a block of memory from one pointer to another.
|
||||||
// }
|
if operands[4].Uint(r) != 0 {
|
||||||
// memmove(dst, src, n*elemSize)
|
// This is a volatile copy/move.
|
||||||
// return int(n)
|
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||||
// }
|
if err != nil {
|
||||||
dstLen := operands[3].Uint(r)
|
return nil, mem, err
|
||||||
srcLen := operands[4].Uint(r)
|
}
|
||||||
elemSize := operands[5].Uint(r)
|
continue
|
||||||
n := srcLen
|
|
||||||
if n > dstLen {
|
|
||||||
n = dstLen
|
|
||||||
}
|
}
|
||||||
if r.debug {
|
nBytes := operands[3].Uint(r)
|
||||||
fmt.Fprintln(os.Stderr, indent+"copy:", operands[1], operands[2], n)
|
if nBytes != 0 {
|
||||||
}
|
|
||||||
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 slices
|
// This is not just an optimization. If one of the pointers
|
||||||
// (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)
|
||||||
@@ -363,11 +358,10 @@ 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 slice is external.
|
// If the buffer is nil, it means the memory 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.
|
||||||
@@ -380,33 +374,10 @@ 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():dst.offset()+nBytes], srcBuf.buf[src.offset():])
|
copy(dstBuf.buf[dst.offset():][:nBytes], srcBuf.buf[src.offset():][:nBytes])
|
||||||
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.
|
||||||
@@ -577,7 +548,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// runtime instead of at compile time. But we need to
|
// runtime instead of at compile time. But we need to
|
||||||
// revert any changes made by the call first.
|
// revert any changes made by the call first.
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Err)
|
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Error())
|
||||||
}
|
}
|
||||||
callMem.revert()
|
callMem.revert()
|
||||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ target triple = "x86_64--linux"
|
|||||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||||
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||||
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
||||||
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
|
@main.negativeGEP = global ptr getelementptr inbounds nuw (i8, ptr @main.negativeGEP, i64 2)
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
|
|||||||
@ptrToIntResult = local_unnamed_addr global i8 2
|
@ptrToIntResult = local_unnamed_addr global i8 2
|
||||||
@pointerTagResult = local_unnamed_addr global i64 2
|
@pointerTagResult = local_unnamed_addr global i64 2
|
||||||
@someArray = internal global { i16, i8, i8 } zeroinitializer
|
@someArray = internal global { i16, i8, i8 } zeroinitializer
|
||||||
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds (i8, ptr @someArray, i64 2)
|
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds nuw (i8, ptr @someArray, i64 2)
|
||||||
|
|
||||||
define void @runtime.initAll() local_unnamed_addr {
|
define void @runtime.initAll() local_unnamed_addr {
|
||||||
ret void
|
ret void
|
||||||
|
|||||||
Vendored
+68
@@ -0,0 +1,68 @@
|
|||||||
|
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)
|
||||||
Vendored
+27
@@ -0,0 +1,27 @@
|
|||||||
|
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) }
|
||||||
Vendored
+52
@@ -0,0 +1,52 @@
|
|||||||
|
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)
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
Vendored
-124
@@ -1,124 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
Vendored
-42
@@ -1,42 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
+1
-1
Submodule lib/bdwgc updated: 1166f11f7d...7577ca7c2d
@@ -291,7 +291,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
|||||||
})
|
})
|
||||||
|
|
||||||
if testConfig.CompileOnly {
|
if testConfig.CompileOnly {
|
||||||
return true, nil
|
// Return the compiler error, if there is one.
|
||||||
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||||
@@ -339,8 +340,17 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
|
|||||||
return dirs
|
return dirs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateOutputFormat checks if the output file extension matches the expected format
|
||||||
|
func validateOutputFormat(outpath, expectedExt string) error {
|
||||||
|
actualExt := filepath.Ext(outpath)
|
||||||
|
if actualExt != expectedExt {
|
||||||
|
return fmt.Errorf("output format %s does not match target format %s", actualExt, expectedExt)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Flash builds and flashes the built binary to the given serial port.
|
// Flash builds and flashes the built binary to the given serial port.
|
||||||
func Flash(pkgName, port string, options *compileopts.Options) error {
|
func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
|
||||||
config, err := builder.NewConfig(options)
|
config, err := builder.NewConfig(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -389,13 +399,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
|||||||
if !options.Work {
|
if !options.Work {
|
||||||
defer os.RemoveAll(tmpdir)
|
defer os.RemoveAll(tmpdir)
|
||||||
}
|
}
|
||||||
|
// Validate output format before building
|
||||||
|
if outpath != "" {
|
||||||
|
if err := validateOutputFormat(outpath, fileExt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
// Build the binary.
|
// Build the binary.
|
||||||
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
|
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save output file if specified (after build, before flashing)
|
||||||
|
if outpath != "" {
|
||||||
|
if err := copyFile(result.Binary, outpath); err != nil {
|
||||||
|
return fmt.Errorf("failed to save output file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
// do we need port reset to put MCU into bootloader mode?
|
// do we need port reset to put MCU into bootloader mode?
|
||||||
if config.Target.PortReset == "true" && flashMethod != "openocd" {
|
if config.Target.PortReset == "true" && flashMethod != "openocd" {
|
||||||
port, err := getDefaultPort(port, config.Target.SerialPort)
|
port, err := getDefaultPort(port, config.Target.SerialPort)
|
||||||
@@ -1297,6 +1318,11 @@ extension at all.`
|
|||||||
(https://tinygo.org/docs/reference/microcontrollers/).
|
(https://tinygo.org/docs/reference/microcontrollers/).
|
||||||
Examples: "arduino-nano", "d1mini", "xiao".
|
Examples: "arduino-nano", "d1mini", "xiao".
|
||||||
|
|
||||||
|
-o={filename}:
|
||||||
|
Save the built binary to the specified output file. The file
|
||||||
|
format must match the target's expected format (e.g., .hex,
|
||||||
|
.uf2). Both flashing and saving will be performed.
|
||||||
|
|
||||||
-monitor:
|
-monitor:
|
||||||
Start the serial monitor (see below) immediately after
|
Start the serial monitor (see below) immediately after
|
||||||
flashing. However, some microcontrollers need a split second
|
flashing. However, some microcontrollers need a split second
|
||||||
@@ -1609,6 +1635,7 @@ func main() {
|
|||||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||||
|
gocompatibility := flag.Bool("go-compatibility", true, "enable to check for Go versions compatibility, you can also configure this by setting the TINYGO_GOCOMPATIBILITY environment variable")
|
||||||
|
|
||||||
// Internal flags, that are only intended for TinyGo development.
|
// Internal flags, that are only intended for TinyGo development.
|
||||||
printIR := flag.Bool("internal-printir", false, "print LLVM IR")
|
printIR := flag.Bool("internal-printir", false, "print LLVM IR")
|
||||||
@@ -1627,7 +1654,7 @@ func main() {
|
|||||||
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
|
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
|
||||||
}
|
}
|
||||||
var outpath string
|
var outpath string
|
||||||
if command == "help" || command == "build" || command == "test" {
|
if command == "help" || command == "build" || command == "test" || command == "flash" {
|
||||||
flag.StringVar(&outpath, "o", "", "output filename")
|
flag.StringVar(&outpath, "o", "", "output filename")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1686,6 +1713,16 @@ func main() {
|
|||||||
ocdCommands = strings.Split(*ocdCommandsString, ",")
|
ocdCommands = strings.Split(*ocdCommandsString, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val, ok := os.LookupEnv("TINYGO_GOCOMPATIBILITY")
|
||||||
|
if ok {
|
||||||
|
b, err := strconv.ParseBool(val)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "could not parse TINYGO_GOCOMPATIBILITY value %q: %v\n", val, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
*gocompatibility = b
|
||||||
|
}
|
||||||
|
|
||||||
options := &compileopts.Options{
|
options := &compileopts.Options{
|
||||||
GOOS: goenv.Get("GOOS"),
|
GOOS: goenv.Get("GOOS"),
|
||||||
GOARCH: goenv.Get("GOARCH"),
|
GOARCH: goenv.Get("GOARCH"),
|
||||||
@@ -1722,6 +1759,7 @@ func main() {
|
|||||||
Timeout: *timeout,
|
Timeout: *timeout,
|
||||||
WITPackage: witPackage,
|
WITPackage: witPackage,
|
||||||
WITWorld: witWorld,
|
WITWorld: witWorld,
|
||||||
|
GoCompatibility: *gocompatibility,
|
||||||
}
|
}
|
||||||
if *printCommands {
|
if *printCommands {
|
||||||
options.PrintCommands = printCommand
|
options.PrintCommands = printCommand
|
||||||
@@ -1778,7 +1816,7 @@ func main() {
|
|||||||
case "flash", "gdb", "lldb":
|
case "flash", "gdb", "lldb":
|
||||||
pkgName := filepath.ToSlash(flag.Arg(0))
|
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||||
if command == "flash" {
|
if command == "flash" {
|
||||||
err := Flash(pkgName, *port, options)
|
err := Flash(pkgName, *port, outpath, options)
|
||||||
printBuildOutput(err, *flagJSON)
|
printBuildOutput(err, *flagJSON)
|
||||||
} else {
|
} else {
|
||||||
if !options.Debug {
|
if !options.Debug {
|
||||||
@@ -1864,6 +1902,7 @@ func main() {
|
|||||||
wd = ""
|
wd = ""
|
||||||
}
|
}
|
||||||
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
|
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if !passed {
|
if !passed {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ 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" {
|
||||||
@@ -424,10 +425,12 @@ func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, environmentVars []string) {
|
func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, environmentVars []string) {
|
||||||
|
t.Helper()
|
||||||
runTestWithConfig(name, t, options, cmdArgs, environmentVars)
|
runTestWithConfig(name, t, options, cmdArgs, environmentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
|
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
|
||||||
|
t.Helper()
|
||||||
// Get the expected output for this test.
|
// Get the expected output for this test.
|
||||||
// Note: not using filepath.Join as it strips the path separator at the end
|
// Note: not using filepath.Join as it strips the path separator at the end
|
||||||
// of the path.
|
// of the path.
|
||||||
@@ -876,6 +879,7 @@ func TestWasmExit(t *testing.T) {
|
|||||||
|
|
||||||
// Check whether the output of a test equals the expected output.
|
// Check whether the output of a test equals the expected output.
|
||||||
func checkOutput(t *testing.T, filename string, actual []byte) {
|
func checkOutput(t *testing.T, filename string, actual []byte) {
|
||||||
|
t.Helper()
|
||||||
expectedOutput, err := os.ReadFile(filename)
|
expectedOutput, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("could not read output file:", err)
|
t.Fatal("could not read output file:", err)
|
||||||
@@ -884,6 +888,7 @@ func checkOutput(t *testing.T, filename string, actual []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkOutputData(t *testing.T, expectedOutput, actual []byte) {
|
func checkOutputData(t *testing.T, expectedOutput, actual []byte) {
|
||||||
|
t.Helper()
|
||||||
expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n"))
|
expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n"))
|
||||||
actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n"))
|
actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n"))
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -35,8 +35,8 @@ func Monitor(executable, port string, config *compileopts.Config) error {
|
|||||||
// Use the RTT interface, which is documented (in part) here:
|
// Use the RTT interface, which is documented (in part) here:
|
||||||
// https://wiki.segger.com/RTT
|
// https://wiki.segger.com/RTT
|
||||||
|
|
||||||
// Try to find the "machine.rttSerialInstance" symbol, which is the RTT
|
// Try to find the "_SEGGER_RTT" symbol (machine.rttSerialInstance)
|
||||||
// control block.
|
// symbol, which is the RTT control block.
|
||||||
file, err := elf.Open(executable)
|
file, err := elf.Open(executable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not open ELF file to determine RTT control block: %w", err)
|
return fmt.Errorf("could not open ELF file to determine RTT control block: %w", err)
|
||||||
@@ -48,7 +48,7 @@ func Monitor(executable, port string, config *compileopts.Config) error {
|
|||||||
}
|
}
|
||||||
var address uint64
|
var address uint64
|
||||||
for _, symbol := range symbols {
|
for _, symbol := range symbols {
|
||||||
if symbol.Name == "machine.rttSerialInstance" {
|
if symbol.Name == "_SEGGER_RTT" {
|
||||||
address = symbol.Value
|
address = symbol.Value
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ func SecCertificateCopyData(cert CFRef) ([]byte, error) {
|
|||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SecTrustCopyCertificateChain(trustObj CFRef) (CFRef, error) {
|
||||||
|
return 0, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
|
func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ func Asm(asm string)
|
|||||||
// recognizes template values in the form {name}, like so:
|
// recognizes template values in the form {name}, like so:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "str {value}, {result}",
|
// "str {value}, [{result}]",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1,
|
||||||
// "result": &dest,
|
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// You can use {} in the asm string (which expands to a register) to set the
|
// You can use {} in the asm string (which expands to a register) to set the
|
||||||
|
|||||||
@@ -1,29 +1,6 @@
|
|||||||
.syntax unified
|
.syntax unified
|
||||||
.cfi_sections .debug_frame
|
.cfi_sections .debug_frame
|
||||||
|
|
||||||
.section .text.HardFault_Handler
|
|
||||||
.global HardFault_Handler
|
|
||||||
.type HardFault_Handler, %function
|
|
||||||
HardFault_Handler:
|
|
||||||
.cfi_startproc
|
|
||||||
// Put the old stack pointer in the first argument, for easy debugging. This
|
|
||||||
// is especially useful on Cortex-M0, which supports far fewer debug
|
|
||||||
// facilities.
|
|
||||||
mov r0, sp
|
|
||||||
|
|
||||||
// Load the default stack pointer from address 0 so that we can call normal
|
|
||||||
// functions again that expect a working stack. However, it will corrupt the
|
|
||||||
// old stack so the function below must not attempt to recover from this
|
|
||||||
// fault.
|
|
||||||
movs r3, #0
|
|
||||||
ldr r3, [r3]
|
|
||||||
mov sp, r3
|
|
||||||
|
|
||||||
// Continue handling this error in Go.
|
|
||||||
bl handleHardFault
|
|
||||||
.cfi_endproc
|
|
||||||
.size HardFault_Handler, .-HardFault_Handler
|
|
||||||
|
|
||||||
// This is a convenience function for semihosting support.
|
// This is a convenience function for semihosting support.
|
||||||
// At some point, this should be replaced by inline assembly.
|
// At some point, this should be replaced by inline assembly.
|
||||||
.section .text.SemihostingCall
|
.section .text.SemihostingCall
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ func Asm(asm string)
|
|||||||
// recognizes template values in the form {name}, like so:
|
// recognizes template values in the form {name}, like so:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "str {value}, {result}",
|
// "str {value}, [{result}]",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1,
|
||||||
// "result": &dest,
|
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// You can use {} in the asm string (which expands to a register) to set the
|
// You can use {} in the asm string (which expands to a register) to set the
|
||||||
|
|||||||
+3
-3
@@ -10,10 +10,10 @@ func Asm(asm string)
|
|||||||
// recognizes template values in the form {name}, like so:
|
// recognizes template values in the form {name}, like so:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "str {value}, {result}",
|
// "str {value}, [{result}]",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1,
|
||||||
// "result": &dest,
|
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// You can use {} in the asm string (which expands to a register) to set the
|
// You can use {} in the asm string (which expands to a register) to set the
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ func Asm(asm string)
|
|||||||
// recognizes template values in the form {name}, like so:
|
// recognizes template values in the form {name}, like so:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "st {value}, {result}",
|
// "st {value}, [{result}]",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1,
|
||||||
// "result": &dest,
|
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// You can use {} in the asm string (which expands to a register) to set the
|
// You can use {} in the asm string (which expands to a register) to set the
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//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
|
||||||
|
)
|
||||||
@@ -8,3 +8,10 @@ import "unsafe"
|
|||||||
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Escape[T any](x T) T {
|
||||||
|
// This function is either implemented in the compiler, or left undefined
|
||||||
|
// for some variation of T. The body of this function should not be compiled
|
||||||
|
// as-is.
|
||||||
|
panic("internal/abi.Escape: unreachable (implemented in the compiler)")
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,29 +5,22 @@ import "unsafe"
|
|||||||
// Internal constants for gc layout
|
// Internal constants for gc layout
|
||||||
// See runtime/gc_precise.go
|
// See runtime/gc_precise.go
|
||||||
|
|
||||||
var (
|
type Layout uintptr
|
||||||
NoPtrs unsafe.Pointer
|
|
||||||
Pointer unsafe.Pointer
|
const (
|
||||||
String unsafe.Pointer
|
// 16-bit int => bits = 4
|
||||||
Slice unsafe.Pointer
|
// 32-bit int => bits = 5
|
||||||
|
// 64-bit int => bits = 6
|
||||||
|
sizeBits = 4 + unsafe.Sizeof(uintptr(0))/4
|
||||||
|
|
||||||
|
ptrAlign = unsafe.Alignof(uintptr(0))
|
||||||
|
|
||||||
|
sizeShift = sizeBits + 1
|
||||||
|
|
||||||
|
NoPtrs = Layout((0 << sizeShift) | (1 << 1) | 1)
|
||||||
|
Pointer = Layout((1 << sizeShift) | ((unsafe.Sizeof(unsafe.Pointer(nil)) / ptrAlign) << 1) | 1)
|
||||||
|
String = Layout((1 << sizeShift) | ((unsafe.Sizeof("") / ptrAlign) << 1) | 1)
|
||||||
|
Slice = Layout((1 << sizeShift) | ((unsafe.Sizeof([]byte{}) / ptrAlign) << 1) | 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func (l Layout) AsPtr() unsafe.Pointer { return unsafe.Pointer(l) }
|
||||||
var sizeBits uintptr
|
|
||||||
|
|
||||||
switch unsafe.Sizeof(uintptr(0)) {
|
|
||||||
case 8:
|
|
||||||
sizeBits = 6
|
|
||||||
case 4:
|
|
||||||
sizeBits = 5
|
|
||||||
case 2:
|
|
||||||
sizeBits = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
var sizeShift = sizeBits + 1
|
|
||||||
|
|
||||||
NoPtrs = unsafe.Pointer(uintptr(0b0<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
|
|
||||||
Pointer = unsafe.Pointer(uintptr(0b1<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
|
|
||||||
String = unsafe.Pointer(uintptr(0b01<<sizeShift) | uintptr(0b10<<1) | uintptr(1))
|
|
||||||
Slice = unsafe.Pointer(uintptr(0b001<<sizeShift) | uintptr(0b11<<1) | uintptr(1))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -708,16 +708,16 @@ func (r *RawType) gcLayout() unsafe.Pointer {
|
|||||||
kind := r.Kind()
|
kind := r.Kind()
|
||||||
|
|
||||||
if kind < String {
|
if kind < String {
|
||||||
return gclayout.NoPtrs
|
return gclayout.NoPtrs.AsPtr()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case Pointer, UnsafePointer, Chan, Map:
|
case Pointer, UnsafePointer, Chan, Map:
|
||||||
return gclayout.Pointer
|
return gclayout.Pointer.AsPtr()
|
||||||
case String:
|
case String:
|
||||||
return gclayout.String
|
return gclayout.String.AsPtr()
|
||||||
case Slice:
|
case Slice:
|
||||||
return gclayout.Slice
|
return gclayout.Slice.AsPtr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown (for now); let the conservative pointer scanning handle it
|
// Unknown (for now); let the conservative pointer scanning handle it
|
||||||
|
|||||||
@@ -86,6 +86,64 @@ func (v Value) Interface() interface{} {
|
|||||||
return valueInterfaceUnsafe(v)
|
return valueInterfaceUnsafe(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TypeAssert[T any](v Value) (T, bool) {
|
||||||
|
if v.typecode == nil {
|
||||||
|
panic("reflect.TypeAssert: zero Value")
|
||||||
|
}
|
||||||
|
if !v.isExported() {
|
||||||
|
// Do not allow access to unexported values via TypeAssert,
|
||||||
|
// because they might be pointers that should not be
|
||||||
|
// writable or methods or function that should not be callable.
|
||||||
|
panic("reflect.TypeAssert: cannot return value obtained from unexported field or method")
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := TypeFor[T]()
|
||||||
|
|
||||||
|
// If v is an interface, return the element inside the interface.
|
||||||
|
//
|
||||||
|
// T is a concrete type and v is an interface. For example:
|
||||||
|
//
|
||||||
|
// var v any = int(1)
|
||||||
|
// val := ValueOf(&v).Elem()
|
||||||
|
// TypeAssert[int](val) == val.Interface().(int)
|
||||||
|
//
|
||||||
|
// T is a interface and v is a non-nil interface value. For example:
|
||||||
|
//
|
||||||
|
// var v any = &someError{}
|
||||||
|
// val := ValueOf(&v).Elem()
|
||||||
|
// TypeAssert[error](val) == val.Interface().(error)
|
||||||
|
//
|
||||||
|
// T is a interface and v is a nil interface value. For example:
|
||||||
|
//
|
||||||
|
// var v error = nil
|
||||||
|
// val := ValueOf(&v).Elem()
|
||||||
|
// TypeAssert[error](val) == val.Interface().(error)
|
||||||
|
if v.Kind() == Interface {
|
||||||
|
val, ok := valueInterfaceUnsafe(v).(T)
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// If T is an interface and v is a concrete type. For example:
|
||||||
|
//
|
||||||
|
// TypeAssert[any](ValueOf(1)) == ValueOf(1).Interface().(any)
|
||||||
|
// TypeAssert[error](ValueOf(&someError{})) == ValueOf(&someError{}).Interface().(error)
|
||||||
|
if typ.Kind() == Interface {
|
||||||
|
val, ok := valueInterfaceUnsafe(v).(T)
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both v and T must be concrete types.
|
||||||
|
// The only way for an type-assertion to match is if the types are equal.
|
||||||
|
if typ != v.typecode {
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
if !v.isIndirect() {
|
||||||
|
return *(*T)(unsafe.Pointer(&v.value)), true
|
||||||
|
}
|
||||||
|
return *(*T)(v.value), true
|
||||||
|
}
|
||||||
|
|
||||||
// valueInterfaceUnsafe is used by the runtime to hash map keys. It should not
|
// valueInterfaceUnsafe is used by the runtime to hash map keys. It should not
|
||||||
// be subject to the isExported check.
|
// be subject to the isExported check.
|
||||||
func valueInterfaceUnsafe(v Value) interface{} {
|
func valueInterfaceUnsafe(v Value) interface{} {
|
||||||
@@ -1738,6 +1796,9 @@ func (e *ValueError) Error() string {
|
|||||||
//go:linkname memcpy runtime.memcpy
|
//go:linkname memcpy runtime.memcpy
|
||||||
func memcpy(dst, src unsafe.Pointer, size uintptr)
|
func memcpy(dst, src unsafe.Pointer, size uintptr)
|
||||||
|
|
||||||
|
//go:linkname memmove runtime.memmove
|
||||||
|
func memmove(dst, src unsafe.Pointer, size uintptr)
|
||||||
|
|
||||||
//go:linkname memzero runtime.memzero
|
//go:linkname memzero runtime.memzero
|
||||||
func memzero(ptr unsafe.Pointer, size uintptr)
|
func memzero(ptr unsafe.Pointer, size uintptr)
|
||||||
|
|
||||||
@@ -1745,10 +1806,7 @@ func memzero(ptr unsafe.Pointer, size uintptr)
|
|||||||
func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
//go:linkname sliceAppend runtime.sliceAppend
|
//go:linkname sliceAppend runtime.sliceAppend
|
||||||
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr)
|
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr)
|
||||||
|
|
||||||
//go:linkname sliceCopy runtime.sliceCopy
|
|
||||||
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int
|
|
||||||
|
|
||||||
// Copy copies the contents of src into dst until either
|
// Copy copies the contents of src into dst until either
|
||||||
// dst has been filled or src has been exhausted.
|
// dst has been filled or src has been exhausted.
|
||||||
@@ -1779,7 +1837,10 @@ func Copy(dst, src Value) int {
|
|||||||
dst.checkRO()
|
dst.checkRO()
|
||||||
}
|
}
|
||||||
|
|
||||||
return sliceCopy(dstbuf, srcbuf, dstlen, srclen, dst.typecode.elem().Size())
|
minLen := min(dstlen, srclen)
|
||||||
|
elemSize := dst.typecode.elem().Size()
|
||||||
|
memmove(dstbuf, srcbuf, minLen*elemSize)
|
||||||
|
return int(minLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buflen(v Value) (unsafe.Pointer, uintptr) {
|
func buflen(v Value) (unsafe.Pointer, uintptr) {
|
||||||
@@ -1810,7 +1871,7 @@ func buflen(v Value) (unsafe.Pointer, uintptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname sliceGrow runtime.sliceGrow
|
//go:linkname sliceGrow runtime.sliceGrow
|
||||||
func sliceGrow(buf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr)
|
func sliceGrow(buf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr)
|
||||||
|
|
||||||
// extend slice to hold n new elements
|
// extend slice to hold n new elements
|
||||||
func extendSlice(v Value, n int) sliceHeader {
|
func extendSlice(v Value, n int) sliceHeader {
|
||||||
@@ -1823,7 +1884,10 @@ func extendSlice(v Value, n int) sliceHeader {
|
|||||||
old = *(*sliceHeader)(v.value)
|
old = *(*sliceHeader)(v.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
nbuf, nlen, ncap := sliceGrow(old.data, old.len, old.cap, old.len+uintptr(n), v.typecode.elem().Size())
|
elem := v.typecode.elem()
|
||||||
|
elemSize := elem.Size()
|
||||||
|
elemLayout := elem.gcLayout()
|
||||||
|
nbuf, nlen, ncap := sliceGrow(old.data, old.len, old.cap, old.len+uintptr(n), elemSize, elemLayout)
|
||||||
|
|
||||||
return sliceHeader{
|
return sliceHeader{
|
||||||
data: nbuf,
|
data: nbuf,
|
||||||
@@ -1862,8 +1926,10 @@ func AppendSlice(s, t Value) Value {
|
|||||||
}
|
}
|
||||||
sSlice := (*sliceHeader)(s.value)
|
sSlice := (*sliceHeader)(s.value)
|
||||||
tSlice := (*sliceHeader)(t.value)
|
tSlice := (*sliceHeader)(t.value)
|
||||||
elemSize := s.typecode.elem().Size()
|
elem := s.typecode.elem()
|
||||||
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize)
|
elemSize := elem.Size()
|
||||||
|
elemLayout := elem.gcLayout()
|
||||||
|
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize, elemLayout)
|
||||||
result := &sliceHeader{
|
result := &sliceHeader{
|
||||||
data: ptr,
|
data: ptr,
|
||||||
len: len,
|
len: len,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package task
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// MacOS uses a pointer so unsafe.Pointer should be fine:
|
||||||
|
//
|
||||||
|
// typedef struct _opaque_pthread_t *__darwin_pthread_t;
|
||||||
|
// typedef __darwin_pthread_t pthread_t;
|
||||||
|
type threadID unsafe.Pointer
|
||||||
@@ -108,6 +108,10 @@ func (*stackState) unwind()
|
|||||||
func (t *Task) Resume() {
|
func (t *Task) Resume() {
|
||||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||||
prevTask := currentTask
|
prevTask := currentTask
|
||||||
|
if prevTask == nil {
|
||||||
|
// Save the system stack pointer.
|
||||||
|
saveStackPointer()
|
||||||
|
}
|
||||||
t.gcData.swap()
|
t.gcData.swap()
|
||||||
currentTask = t
|
currentTask = t
|
||||||
if !t.state.launched {
|
if !t.state.launched {
|
||||||
@@ -123,6 +127,9 @@ func (t *Task) Resume() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname saveStackPointer runtime.saveStackPointer
|
||||||
|
func saveStackPointer()
|
||||||
|
|
||||||
//export tinygo_rewind
|
//export tinygo_rewind
|
||||||
func (*state) rewind()
|
func (*state) rewind()
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build scheduler.tasks && esp32
|
//go:build scheduler.tasks && (esp32 || esp32s3)
|
||||||
|
|
||||||
package task
|
package task
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,28 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <semaphore.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice.
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
// BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice.
|
||||||
#define taskPauseSignal (SIGRTMIN + 6)
|
#define taskPauseSignal (SIGRTMIN + 6)
|
||||||
#endif
|
|
||||||
|
#elif __APPLE__
|
||||||
|
#include <dispatch/dispatch.h>
|
||||||
|
// SIGIO is for interrupt-driven I/O.
|
||||||
|
// I don't think anybody should be using this nowadays, so I think we can
|
||||||
|
// repurpose it as a signal for GC.
|
||||||
|
// BDWGC uses a special way to pause/resume other threads on MacOS, which may be
|
||||||
|
// better but needs more work. Using signal keeps the code similar between Linux
|
||||||
|
// and MacOS.
|
||||||
|
#define taskPauseSignal SIGIO
|
||||||
|
|
||||||
|
#endif // __linux__, __APPLE__
|
||||||
|
|
||||||
// Pointer to the current task.Task structure.
|
// Pointer to the current task.Task structure.
|
||||||
// Ideally the entire task.Task structure would be a thread-local variable but
|
// Ideally the entire task.Task structure would be a thread-local variable but
|
||||||
@@ -23,7 +35,11 @@ struct state_pass {
|
|||||||
void *args;
|
void *args;
|
||||||
void *task;
|
void *task;
|
||||||
uintptr_t *stackTop;
|
uintptr_t *stackTop;
|
||||||
|
#if __APPLE__
|
||||||
|
dispatch_semaphore_t startlock;
|
||||||
|
#else
|
||||||
sem_t startlock;
|
sem_t startlock;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle the GC pause in Go.
|
// Handle the GC pause in Go.
|
||||||
@@ -41,8 +57,8 @@ void tinygo_task_init(void *mainTask, pthread_t *thread, int *numCPU, void *cont
|
|||||||
// Register the "GC pause" signal for the entire process.
|
// Register the "GC pause" signal for the entire process.
|
||||||
// Using pthread_kill, we can still send the signal to a specific thread.
|
// Using pthread_kill, we can still send the signal to a specific thread.
|
||||||
struct sigaction act = { 0 };
|
struct sigaction act = { 0 };
|
||||||
act.sa_flags = SA_SIGINFO;
|
act.sa_handler = tinygo_task_gc_pause;
|
||||||
act.sa_handler = &tinygo_task_gc_pause;
|
act.sa_flags = SA_RESTART;
|
||||||
sigaction(taskPauseSignal, &act, NULL);
|
sigaction(taskPauseSignal, &act, NULL);
|
||||||
|
|
||||||
// Obtain the number of CPUs available on program start (for NumCPU).
|
// Obtain the number of CPUs available on program start (for NumCPU).
|
||||||
@@ -69,7 +85,11 @@ static void* start_wrapper(void *arg) {
|
|||||||
|
|
||||||
// Notify the caller that the thread has successfully started and
|
// Notify the caller that the thread has successfully started and
|
||||||
// initialized.
|
// initialized.
|
||||||
|
#if __APPLE__
|
||||||
|
dispatch_semaphore_signal(state->startlock);
|
||||||
|
#else
|
||||||
sem_post(&state->startlock);
|
sem_post(&state->startlock);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Run the goroutine function.
|
// Run the goroutine function.
|
||||||
start(args);
|
start(args);
|
||||||
@@ -81,7 +101,7 @@ static void* start_wrapper(void *arg) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Start a new goroutine in an OS thread.
|
// Start a new goroutine in an OS thread.
|
||||||
int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, uintptr_t *stackTop, void *context) {
|
int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, uintptr_t *stackTop, uintptr_t stackSize, void *context) {
|
||||||
// Sanity check. Should get optimized away.
|
// Sanity check. Should get optimized away.
|
||||||
if (sizeof(pthread_t) != sizeof(void*)) {
|
if (sizeof(pthread_t) != sizeof(void*)) {
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
@@ -93,11 +113,29 @@ int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, u
|
|||||||
.task = task,
|
.task = task,
|
||||||
.stackTop = stackTop,
|
.stackTop = stackTop,
|
||||||
};
|
};
|
||||||
|
#if __APPLE__
|
||||||
|
state.startlock = dispatch_semaphore_create(0);
|
||||||
|
#else
|
||||||
sem_init(&state.startlock, 0, 0);
|
sem_init(&state.startlock, 0, 0);
|
||||||
int result = pthread_create(thread, NULL, &start_wrapper, &state);
|
#endif
|
||||||
|
pthread_attr_t attrs;
|
||||||
|
pthread_attr_init(&attrs);
|
||||||
|
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
|
||||||
|
pthread_attr_setstacksize(&attrs, stackSize);
|
||||||
|
int result = pthread_create(thread, &attrs, &start_wrapper, &state);
|
||||||
|
pthread_attr_destroy(&attrs);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Wait until the thread has been created and read all state_pass variables.
|
// Wait until the thread has been created and read all state_pass variables.
|
||||||
|
#if __APPLE__
|
||||||
|
dispatch_semaphore_wait(state.startlock, DISPATCH_TIME_FOREVER);
|
||||||
|
dispatch_release(state.startlock);
|
||||||
|
#else
|
||||||
sem_wait(&state.startlock);
|
sem_wait(&state.startlock);
|
||||||
|
sem_destroy(&state.startlock);
|
||||||
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,16 +23,15 @@ type state struct {
|
|||||||
// is needed to be able to scan the stack.
|
// is needed to be able to scan the stack.
|
||||||
stackTop uintptr
|
stackTop uintptr
|
||||||
|
|
||||||
|
// Lowest address of the stack.
|
||||||
|
// This is populated when the thread is stopped by the GC.
|
||||||
|
stackBottom uintptr
|
||||||
|
|
||||||
// Next task in the activeTasks queue.
|
// Next task in the activeTasks queue.
|
||||||
QueueNext *Task
|
QueueNext *Task
|
||||||
|
|
||||||
// Semaphore to pause/resume the thread atomically.
|
// Semaphore to pause/resume the thread atomically.
|
||||||
pauseSem Semaphore
|
pauseSem Semaphore
|
||||||
|
|
||||||
// Semaphore used for stack scanning.
|
|
||||||
// We can't reuse pauseSem here since the thread might have been paused for
|
|
||||||
// other reasons (for example, because it was waiting on a channel).
|
|
||||||
gcSem Semaphore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goroutine counter, starting at 0 for the main goroutine.
|
// Goroutine counter, starting at 0 for the main goroutine.
|
||||||
@@ -96,6 +95,9 @@ func (t *Task) Resume() {
|
|||||||
t.state.pauseSem.Post()
|
t.state.pauseSem.Post()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherGoroutines is the total number of live goroutines minus one.
|
||||||
|
var otherGoroutines uint32
|
||||||
|
|
||||||
// Start a new OS thread.
|
// Start a new OS thread.
|
||||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||||
t := &Task{}
|
t := &Task{}
|
||||||
@@ -109,12 +111,13 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
|||||||
// and the stop-the-world GC won't see threads that haven't started yet or
|
// and the stop-the-world GC won't see threads that haven't started yet or
|
||||||
// are not fully started yet.
|
// are not fully started yet.
|
||||||
activeTaskLock.Lock()
|
activeTaskLock.Lock()
|
||||||
errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop)
|
errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop, stackSize)
|
||||||
if errCode != 0 {
|
if errCode != 0 {
|
||||||
runtimePanic("could not start thread")
|
runtimePanic("could not start thread")
|
||||||
}
|
}
|
||||||
t.state.QueueNext = activeTasks
|
t.state.QueueNext = activeTasks
|
||||||
activeTasks = t
|
activeTasks = t
|
||||||
|
otherGoroutines++
|
||||||
activeTaskLock.Unlock()
|
activeTaskLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +138,7 @@ func taskExited(t *Task) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
otherGoroutines--
|
||||||
activeTaskLock.Unlock()
|
activeTaskLock.Unlock()
|
||||||
|
|
||||||
// Sanity check.
|
// Sanity check.
|
||||||
@@ -143,9 +147,42 @@ func taskExited(t *Task) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Futex to wait on until all tasks have finished scanning the stack.
|
// scanWaitGroup is used to wait on until all threads have finished the current state transition.
|
||||||
// This is basically a sync.WaitGroup.
|
var scanWaitGroup waitGroup
|
||||||
var scanDoneFutex Futex
|
|
||||||
|
type waitGroup struct {
|
||||||
|
f Futex
|
||||||
|
}
|
||||||
|
|
||||||
|
func initWaitGroup(n uint32) waitGroup {
|
||||||
|
var wg waitGroup
|
||||||
|
wg.f.Store(n)
|
||||||
|
return wg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *waitGroup) done() {
|
||||||
|
if wg.f.Add(^uint32(0)) == 0 {
|
||||||
|
wg.f.WakeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *waitGroup) wait() {
|
||||||
|
for {
|
||||||
|
val := wg.f.Load()
|
||||||
|
if val == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wg.f.Wait(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gcState is used to track and notify threads when the GC is stopping/resuming.
|
||||||
|
var gcState Futex
|
||||||
|
|
||||||
|
const (
|
||||||
|
gcStateResumed = iota
|
||||||
|
gcStateStopped
|
||||||
|
)
|
||||||
|
|
||||||
// GC scan phase. Because we need to stop the world while scanning, this kinda
|
// GC scan phase. Because we need to stop the world while scanning, this kinda
|
||||||
// needs to be done in the tasks package.
|
// needs to be done in the tasks package.
|
||||||
@@ -155,100 +192,99 @@ var scanDoneFutex Futex
|
|||||||
func GCStopWorldAndScan() {
|
func GCStopWorldAndScan() {
|
||||||
current := Current()
|
current := Current()
|
||||||
|
|
||||||
// Don't allow new goroutines to be started while pausing/resuming threads
|
// NOTE: This does not need to be atomic.
|
||||||
// in the stop-the-world phase.
|
if gcState.Load() == gcStateResumed {
|
||||||
activeTaskLock.Lock()
|
// Don't allow new goroutines to be started while pausing/resuming threads
|
||||||
|
// in the stop-the-world phase.
|
||||||
|
activeTaskLock.Lock()
|
||||||
|
|
||||||
// Pause all other threads.
|
// Wait for threads to finish resuming.
|
||||||
numOtherThreads := uint32(0)
|
scanWaitGroup.wait()
|
||||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
|
||||||
if t != current {
|
// Change the gc state to stopped.
|
||||||
numOtherThreads++
|
// NOTE: This does not need to be atomic.
|
||||||
tinygo_task_send_gc_signal(t.state.thread)
|
gcState.Store(gcStateStopped)
|
||||||
|
|
||||||
|
// Set the number of threads to wait for.
|
||||||
|
scanWaitGroup = initWaitGroup(otherGoroutines)
|
||||||
|
|
||||||
|
// Pause all other threads.
|
||||||
|
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||||
|
if t != current {
|
||||||
|
tinygo_task_send_gc_signal(t.state.thread)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the threads to finish stopping.
|
||||||
|
scanWaitGroup.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the number of threads to wait for in the futex.
|
// Scan other thread stacks.
|
||||||
// This is the equivalent of doing an initial wg.Add(numOtherThreads).
|
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||||
scanDoneFutex.Store(numOtherThreads)
|
if t != current {
|
||||||
|
markRoots(t.state.stackBottom, t.state.stackTop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scan the current stack, and all current registers.
|
// Scan the current stack, and all current registers.
|
||||||
scanCurrentStack()
|
scanCurrentStack()
|
||||||
|
|
||||||
// Wake each paused thread for the first time so it will scan the stack.
|
|
||||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
|
||||||
if t != current {
|
|
||||||
t.state.gcSem.Post()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until all threads have finished scanning their stack.
|
|
||||||
// This is the equivalent of wg.Wait()
|
|
||||||
for {
|
|
||||||
val := scanDoneFutex.Load()
|
|
||||||
if val == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
scanDoneFutex.Wait(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan all globals (implemented in the runtime).
|
// Scan all globals (implemented in the runtime).
|
||||||
gcScanGlobals()
|
gcScanGlobals()
|
||||||
}
|
}
|
||||||
|
|
||||||
// After the GC is done scanning, resume all other threads.
|
// After the GC is done scanning, resume all other threads.
|
||||||
//
|
|
||||||
// This must only be called after a GCStopWorldAndScan call.
|
|
||||||
func GCResumeWorld() {
|
func GCResumeWorld() {
|
||||||
current := Current()
|
// NOTE: This does not need to be atomic.
|
||||||
|
if gcState.Load() == gcStateResumed {
|
||||||
// Wake each paused thread for the second time, so they will resume normal
|
// This is already resumed.
|
||||||
// operation.
|
return
|
||||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
|
||||||
if t != current {
|
|
||||||
t.state.gcSem.Post()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the wait group to track resume progress.
|
||||||
|
scanWaitGroup = initWaitGroup(otherGoroutines)
|
||||||
|
|
||||||
|
// Set the state to resumed.
|
||||||
|
gcState.Store(gcStateResumed)
|
||||||
|
|
||||||
|
// Wake all of the stopped threads.
|
||||||
|
gcState.WakeAll()
|
||||||
|
|
||||||
// Allow goroutines to start and exit again.
|
// Allow goroutines to start and exit again.
|
||||||
activeTaskLock.Unlock()
|
activeTaskLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname markRoots runtime.markRoots
|
||||||
|
func markRoots(start, end uintptr)
|
||||||
|
|
||||||
// Scan globals, implemented in the runtime package.
|
// Scan globals, implemented in the runtime package.
|
||||||
func gcScanGlobals()
|
func gcScanGlobals()
|
||||||
|
|
||||||
var stackScanLock PMutex
|
var stackScanLock PMutex
|
||||||
|
|
||||||
//export tinygo_task_gc_pause
|
//export tinygo_task_gc_pause
|
||||||
func tingyo_task_gc_pause() {
|
func tingyo_task_gc_pause(sig int32) {
|
||||||
// Wait until we get the signal to start scanning the stack.
|
// Write the entrty stack pointer to the state.
|
||||||
Current().state.gcSem.Wait()
|
Current().state.stackBottom = uintptr(stacksave())
|
||||||
|
|
||||||
// Scan the thread stack.
|
// Notify the GC that we are stopped.
|
||||||
// Only scan a single thread stack at a time, because the GC marking phase
|
scanWaitGroup.done()
|
||||||
// doesn't support parallelism.
|
|
||||||
// TODO: it may be possible to call markRoots directly (without saving
|
|
||||||
// registers) since we are in a signal handler that already saved a bunch of
|
|
||||||
// registers. This is an optimization left for a future time.
|
|
||||||
stackScanLock.Lock()
|
|
||||||
scanCurrentStack()
|
|
||||||
stackScanLock.Unlock()
|
|
||||||
|
|
||||||
// Equivalent of wg.Done(): subtract one from the futex and if the result is
|
// Wait for the GC to resume.
|
||||||
// 0 (meaning we were the last in the waitgroup), wake the waiting thread.
|
for gcState.Load() == gcStateStopped {
|
||||||
n := uint32(1)
|
gcState.Wait(gcStateStopped)
|
||||||
if scanDoneFutex.Add(-n) == 0 {
|
|
||||||
scanDoneFutex.Wake()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until we get the signal we can resume normally (after the mark phase
|
// Notify the GC that we have resumed.
|
||||||
// has finished).
|
scanWaitGroup.done()
|
||||||
Current().state.gcSem.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export tinygo_scanCurrentStack
|
//go:export tinygo_scanCurrentStack
|
||||||
func scanCurrentStack()
|
func scanCurrentStack()
|
||||||
|
|
||||||
|
//go:linkname stacksave runtime.stacksave
|
||||||
|
func stacksave() unsafe.Pointer
|
||||||
|
|
||||||
// Return the highest address of the current stack.
|
// Return the highest address of the current stack.
|
||||||
func StackTop() uintptr {
|
func StackTop() uintptr {
|
||||||
return Current().state.stackTop
|
return Current().state.stackTop
|
||||||
@@ -266,7 +302,7 @@ func tinygo_task_init(t *Task, thread *threadID, numCPU *int32)
|
|||||||
// Here same as for tinygo_task_init.
|
// Here same as for tinygo_task_init.
|
||||||
//
|
//
|
||||||
//go:linkname tinygo_task_start tinygo_task_start
|
//go:linkname tinygo_task_start tinygo_task_start
|
||||||
func tinygo_task_start(fn uintptr, args unsafe.Pointer, t *Task, thread *threadID, stackTop *uintptr) int32
|
func tinygo_task_start(fn uintptr, args unsafe.Pointer, t *Task, thread *threadID, stackTop *uintptr, stackSize uintptr) int32
|
||||||
|
|
||||||
// Pause the thread by sending it a signal.
|
// Pause the thread by sending it a signal.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
//go:build amken_trio
|
||||||
|
|
||||||
|
// RabbitPNP Toolhead Board
|
||||||
|
// MCU: STM32G0B1CBTx (LQFP48, 128KB Flash, 144KB RAM)
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Vacuum sensors (PWM input via TIM2)
|
||||||
|
const (
|
||||||
|
VAC1 = PA0 // TIM2_CH1
|
||||||
|
VAC2 = PA1 // TIM2_CH2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Motor 1 pins (stepper driver)
|
||||||
|
const (
|
||||||
|
M1_CS = PC7
|
||||||
|
M1_DIR = PB13 // REFL
|
||||||
|
M1_STEP = PB14 // REFR
|
||||||
|
M1_ENN = PA10 // Enable (active low)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Motor 2 pins (stepper driver)
|
||||||
|
const (
|
||||||
|
M2_CS = PA9
|
||||||
|
M2_DIR = PB12 // REFL
|
||||||
|
M2_STEP = PB11 // REFR
|
||||||
|
M2_ENN = PC6 // Enable (active low)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Motor 3 pins (stepper driver)
|
||||||
|
const (
|
||||||
|
M3_CS = PB15
|
||||||
|
M3_DIR = PB2 // REFL
|
||||||
|
M3_STEP = PB1 // REFR
|
||||||
|
M3_ENN = PA8 // Enable (active low)
|
||||||
|
)
|
||||||
|
|
||||||
|
// LED
|
||||||
|
const (
|
||||||
|
LED = LED1
|
||||||
|
LED_BUILTIN = LED1
|
||||||
|
LED1 = PB7
|
||||||
|
)
|
||||||
|
|
||||||
|
// Solenoid and Neopixel (PWM via TIM4)
|
||||||
|
const (
|
||||||
|
SOLENOID = PB8 // TIM4_CH3
|
||||||
|
NEOPIXEL = PB9 // TIM4_CH4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Endstops
|
||||||
|
const (
|
||||||
|
ENDSTOP_IN1 = PC13
|
||||||
|
ENDSTOP_IN2 = PC14
|
||||||
|
)
|
||||||
|
|
||||||
|
// Magnetic sensor
|
||||||
|
const (
|
||||||
|
MAG1 = PB3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Accelerometer chip select (LIS2D on SPI2)
|
||||||
|
const (
|
||||||
|
LIS2D_CS = PB5
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI1 pins (motor drivers)
|
||||||
|
const (
|
||||||
|
SPI1_SCK_PIN = PA5
|
||||||
|
SPI1_SDO_PIN = PA2 // MOSI
|
||||||
|
SPI1_SDI_PIN = PA6 // MISO
|
||||||
|
SPI0_SCK_PIN = SPI1_SCK_PIN
|
||||||
|
SPI0_SDO_PIN = SPI1_SDO_PIN
|
||||||
|
SPI0_SDI_PIN = SPI1_SDI_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI2 pins (accelerometer)
|
||||||
|
const (
|
||||||
|
SPI2_SCK_PIN = PB10
|
||||||
|
SPI2_SDO_PIN = PA4 // MOSI
|
||||||
|
SPI2_SDI_PIN = PA3 // MISO
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C2 pins
|
||||||
|
const (
|
||||||
|
I2C2_SCL_PIN = PA7
|
||||||
|
I2C2_SDA_PIN = PB4
|
||||||
|
I2C0_SCL_PIN = I2C2_SCL_PIN
|
||||||
|
I2C0_SDA_PIN = I2C2_SDA_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// FDCAN1 pins
|
||||||
|
const (
|
||||||
|
CAN_RX = PD0
|
||||||
|
CAN_TX = PD1
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB pins
|
||||||
|
const (
|
||||||
|
USB_DM = PA11
|
||||||
|
USB_DP = PA12
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART pins (not directly connected but required by machine package)
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = NoPin
|
||||||
|
UART_RX_PIN = NoPin
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SPI1 for motor drivers
|
||||||
|
SPI1 = &SPI{
|
||||||
|
Bus: stm32.SPI1,
|
||||||
|
AltFuncSelector: AF0_SYSTEM,
|
||||||
|
}
|
||||||
|
SPI0 = SPI1
|
||||||
|
|
||||||
|
// SPI2 for accelerometer
|
||||||
|
SPI2 = &SPI{
|
||||||
|
Bus: stm32.SPI2,
|
||||||
|
AltFuncSelector: AF1_TIM1_TIM2_TIM3_LPTIM1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C2
|
||||||
|
I2C2 = &I2C{
|
||||||
|
Bus: stm32.I2C2,
|
||||||
|
AltFuncSelector: AF6_SPI2_USART3_USART4_I2C1,
|
||||||
|
}
|
||||||
|
I2C0 = I2C2
|
||||||
|
|
||||||
|
// FDCAN1 on PD0 (RX) / PD1 (TX) with onboard transceiver
|
||||||
|
CAN1 = &_CAN1
|
||||||
|
_CAN1 = FDCAN{
|
||||||
|
Bus: stm32.FDCAN1,
|
||||||
|
TxAltFuncSelect: AF3_FDCAN1_FDCAN2,
|
||||||
|
RxAltFuncSelect: AF3_FDCAN1_FDCAN2,
|
||||||
|
instance: 0,
|
||||||
|
}
|
||||||
|
// Alias for convenience
|
||||||
|
CAN0 = CAN1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suppress unused import warning for interrupt package
|
||||||
|
var _ = interrupt.New
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// No UART configured on this board - uses USB or CAN for communication
|
||||||
|
}
|
||||||
@@ -27,8 +27,8 @@ const (
|
|||||||
PC1 = portC + 1
|
PC1 = portC + 1
|
||||||
PC2 = portC + 2
|
PC2 = portC + 2
|
||||||
PC3 = portC + 3
|
PC3 = portC + 3
|
||||||
PC4 = portC + 4
|
PC4 = portC + 4 // peripherals: I2C0 SDA
|
||||||
PC5 = portC + 5
|
PC5 = portC + 5 // peripherals: I2C0 SCL
|
||||||
PC6 = portC + 6
|
PC6 = portC + 6
|
||||||
PC7 = portC + 7
|
PC7 = portC + 7
|
||||||
PD0 = portD + 0
|
PD0 = portD + 0
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ const (
|
|||||||
PC1 = portC + 1
|
PC1 = portC + 1
|
||||||
PC2 = portC + 2
|
PC2 = portC + 2
|
||||||
PC3 = portC + 3
|
PC3 = portC + 3
|
||||||
PC4 = portC + 4
|
PC4 = portC + 4 // peripherals: I2C0 SDA
|
||||||
PC5 = portC + 5
|
PC5 = portC + 5 // peripherals: I2C0 SCL
|
||||||
PC6 = portC + 6
|
PC6 = portC + 6
|
||||||
PC7 = portC + 7
|
PC7 = portC + 7
|
||||||
PD0 = portD + 0
|
PD0 = portD + 0
|
||||||
@@ -40,8 +40,8 @@ const (
|
|||||||
PD5 = portD + 5 // peripherals: Timer0 channel B
|
PD5 = portD + 5 // peripherals: Timer0 channel B
|
||||||
PD6 = portD + 6 // peripherals: Timer0 channel A
|
PD6 = portD + 6 // peripherals: Timer0 channel A
|
||||||
PD7 = portD + 7
|
PD7 = portD + 7
|
||||||
PE0 = portE + 0
|
PE0 = portE + 0 // peripherals: I2C1 SDA
|
||||||
PE1 = portE + 1
|
PE1 = portE + 1 // peripherals: I2C1 SCL
|
||||||
PE2 = portE + 2
|
PE2 = portE + 2
|
||||||
PE3 = portE + 3
|
PE3 = portE + 3
|
||||||
PE4 = portE + 4
|
PE4 = portE + 4
|
||||||
|
|||||||
@@ -7,32 +7,36 @@ func CPUFrequency() uint32 {
|
|||||||
return 48000000
|
return 48000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that the below pins have a few I2C pins listed that according to the
|
||||||
|
// datasheet don't support I2C yet they are used in practice on boards from
|
||||||
|
// Adafruit and Arduino. See machine_atsamd21_simulator.go for details.
|
||||||
|
|
||||||
// Hardware pins
|
// Hardware pins
|
||||||
const (
|
const (
|
||||||
PA00 Pin = 0 // peripherals: TCC2 channel 0
|
PA00 Pin = 0 // peripherals: TCC2 channel 0, sercomI2CM1 SDA
|
||||||
PA01 Pin = 1 // peripherals: TCC2 channel 1
|
PA01 Pin = 1 // peripherals: TCC2 channel 1, sercomI2CM1 SCL
|
||||||
PA02 Pin = 2
|
PA02 Pin = 2
|
||||||
PA03 Pin = 3
|
PA03 Pin = 3
|
||||||
PA04 Pin = 4 // peripherals: TCC0 channel 0
|
PA04 Pin = 4 // peripherals: TCC0 channel 0
|
||||||
PA05 Pin = 5 // peripherals: TCC0 channel 1
|
PA05 Pin = 5 // peripherals: TCC0 channel 1
|
||||||
PA06 Pin = 6 // peripherals: TCC1 channel 0
|
PA06 Pin = 6 // peripherals: TCC1 channel 0
|
||||||
PA07 Pin = 7 // peripherals: TCC1 channel 1
|
PA07 Pin = 7 // peripherals: TCC1 channel 1
|
||||||
PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 2
|
PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 2, sercomI2CM0 SDA, sercomI2CM2 SDA
|
||||||
PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 3
|
PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 3, sercomI2CM0 SCL, sercomI2CM2 SCL
|
||||||
PA10 Pin = 10 // peripherals: TCC1 channel 0, TCC0 channel 2
|
PA10 Pin = 10 // peripherals: TCC1 channel 0, TCC0 channel 2
|
||||||
PA11 Pin = 11 // peripherals: TCC1 channel 1, TCC0 channel 3
|
PA11 Pin = 11 // peripherals: TCC1 channel 1, TCC0 channel 3
|
||||||
PA12 Pin = 12 // peripherals: TCC2 channel 0, TCC0 channel 2
|
PA12 Pin = 12 // peripherals: TCC2 channel 0, TCC0 channel 2, sercomI2CM2 SDA, sercomI2CM4 SDA
|
||||||
PA13 Pin = 13 // peripherals: TCC2 channel 1, TCC0 channel 3
|
PA13 Pin = 13 // peripherals: TCC2 channel 1, TCC0 channel 3, sercomI2CM2 SCL, sercomI2CM4 SCL
|
||||||
PA14 Pin = 14 // peripherals: TCC0 channel 0
|
PA14 Pin = 14 // peripherals: TCC0 channel 0
|
||||||
PA15 Pin = 15 // peripherals: TCC0 channel 1
|
PA15 Pin = 15 // peripherals: TCC0 channel 1
|
||||||
PA16 Pin = 16 // peripherals: TCC2 channel 0, TCC0 channel 2
|
PA16 Pin = 16 // peripherals: TCC2 channel 0, TCC0 channel 2, sercomI2CM1 SDA, sercomI2CM3 SDA
|
||||||
PA17 Pin = 17 // peripherals: TCC2 channel 1, TCC0 channel 3
|
PA17 Pin = 17 // peripherals: TCC2 channel 1, TCC0 channel 3, sercomI2CM1 SCL, sercomI2CM3 SCL
|
||||||
PA18 Pin = 18 // peripherals: TCC0 channel 2
|
PA18 Pin = 18 // peripherals: TCC0 channel 2
|
||||||
PA19 Pin = 19 // peripherals: TCC0 channel 3
|
PA19 Pin = 19 // peripherals: TCC0 channel 3
|
||||||
PA20 Pin = 20 // peripherals: TCC0 channel 2
|
PA20 Pin = 20 // peripherals: TCC0 channel 2
|
||||||
PA21 Pin = 21 // peripherals: TCC0 channel 3
|
PA21 Pin = 21 // peripherals: TCC0 channel 3
|
||||||
PA22 Pin = 22 // peripherals: TCC0 channel 0
|
PA22 Pin = 22 // peripherals: TCC0 channel 0, sercomI2CM3 SDA, sercomI2CM5 SDA
|
||||||
PA23 Pin = 23 // peripherals: TCC0 channel 1
|
PA23 Pin = 23 // peripherals: TCC0 channel 1, sercomI2CM3 SCL, sercomI2CM5 SCL
|
||||||
PA24 Pin = 24 // peripherals: TCC1 channel 2
|
PA24 Pin = 24 // peripherals: TCC1 channel 2
|
||||||
PA25 Pin = 25 // peripherals: TCC1 channel 3
|
PA25 Pin = 25 // peripherals: TCC1 channel 3
|
||||||
PA26 Pin = 26
|
PA26 Pin = 26
|
||||||
@@ -43,22 +47,22 @@ const (
|
|||||||
PA31 Pin = 31 // peripherals: TCC1 channel 1
|
PA31 Pin = 31 // peripherals: TCC1 channel 1
|
||||||
PB00 Pin = 32
|
PB00 Pin = 32
|
||||||
PB01 Pin = 33
|
PB01 Pin = 33
|
||||||
PB02 Pin = 34
|
PB02 Pin = 34 // peripherals: sercomI2CM5 SDA
|
||||||
PB03 Pin = 35
|
PB03 Pin = 35 // peripherals: sercomI2CM5 SCL
|
||||||
PB04 Pin = 36
|
PB04 Pin = 36
|
||||||
PB05 Pin = 37
|
PB05 Pin = 37
|
||||||
PB06 Pin = 38
|
PB06 Pin = 38
|
||||||
PB07 Pin = 39
|
PB07 Pin = 39
|
||||||
PB08 Pin = 40
|
PB08 Pin = 40 // peripherals: sercomI2CM4 SDA
|
||||||
PB09 Pin = 41
|
PB09 Pin = 41 // peripherals: sercomI2CM4 SCL
|
||||||
PB10 Pin = 42 // peripherals: TCC0 channel 0
|
PB10 Pin = 42 // peripherals: TCC0 channel 0
|
||||||
PB11 Pin = 43 // peripherals: TCC0 channel 1
|
PB11 Pin = 43 // peripherals: TCC0 channel 1
|
||||||
PB12 Pin = 44 // peripherals: TCC0 channel 2
|
PB12 Pin = 44 // peripherals: TCC0 channel 2, sercomI2CM4 SDA
|
||||||
PB13 Pin = 45 // peripherals: TCC0 channel 3
|
PB13 Pin = 45 // peripherals: TCC0 channel 3, sercomI2CM4 SCL
|
||||||
PB14 Pin = 46
|
PB14 Pin = 46
|
||||||
PB15 Pin = 47
|
PB15 Pin = 47
|
||||||
PB16 Pin = 48 // peripherals: TCC0 channel 0
|
PB16 Pin = 48 // peripherals: TCC0 channel 0, sercomI2CM5 SDA
|
||||||
PB17 Pin = 49 // peripherals: TCC0 channel 1
|
PB17 Pin = 49 // peripherals: TCC0 channel 1, sercomI2CM5 SCL
|
||||||
PB18 Pin = 50
|
PB18 Pin = 50
|
||||||
PB19 Pin = 51
|
PB19 Pin = 51
|
||||||
PB20 Pin = 52
|
PB20 Pin = 52
|
||||||
@@ -71,6 +75,6 @@ const (
|
|||||||
PB27 Pin = 59
|
PB27 Pin = 59
|
||||||
PB28 Pin = 60
|
PB28 Pin = 60
|
||||||
PB29 Pin = 61
|
PB29 Pin = 61
|
||||||
PB30 Pin = 62 // peripherals: TCC0 channel 0, TCC1 channel 2
|
PB30 Pin = 62 // peripherals: TCC0 channel 0, TCC1 channel 2, sercomI2CM5 SDA
|
||||||
PB31 Pin = 63 // peripherals: TCC0 channel 1, TCC1 channel 3
|
PB31 Pin = 63 // peripherals: TCC0 channel 1, TCC1 channel 3, sercomI2CM5 SCL
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,17 +2,26 @@
|
|||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
|
// Digispark is a tiny ATtiny85-based board with 6 I/O pins.
|
||||||
|
//
|
||||||
|
// PWM is available on the following pins:
|
||||||
|
// - P0 (PB0): Timer0 channel A
|
||||||
|
// - P1 (PB1): Timer0 channel B or Timer1 channel A (LED pin)
|
||||||
|
// - P4 (PB4): Timer1 channel B
|
||||||
|
//
|
||||||
|
// Timer1 is recommended for PWM as it provides more flexible frequency control.
|
||||||
|
|
||||||
// Return the current CPU frequency in hertz.
|
// Return the current CPU frequency in hertz.
|
||||||
func CPUFrequency() uint32 {
|
func CPUFrequency() uint32 {
|
||||||
return 16000000
|
return 16000000
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
P0 Pin = PB0
|
P0 Pin = PB0 // PWM available (Timer0 OC0A)
|
||||||
P1 Pin = PB1
|
P1 Pin = PB1 // PWM available (Timer0 OC0B or Timer1 OC1A)
|
||||||
P2 Pin = PB2
|
P2 Pin = PB2
|
||||||
P3 Pin = PB3
|
P3 Pin = PB3
|
||||||
P4 Pin = PB4
|
P4 Pin = PB4 // PWM available (Timer1 OC1B)
|
||||||
P5 Pin = PB5
|
P5 Pin = PB5
|
||||||
|
|
||||||
LED = P1
|
LED = P1
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//go:build esp32s3_wroom1
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const (
|
||||||
|
SPI1_SCK_PIN = GPIO12 // SCK
|
||||||
|
SPI1_MOSI_PIN = GPIO11 // SDO (MOSI)
|
||||||
|
SPI1_MISO_PIN = GPIO13 // SDI (MISO)
|
||||||
|
SPI1_CS_PIN = GPIO10 // CS
|
||||||
|
|
||||||
|
SPI2_SCK_PIN = GPIO36 // SCK
|
||||||
|
SPI2_MOSI_PIN = GPIO35 // SDO (MOSI)
|
||||||
|
SPI2_MISO_PIN = GPIO37 // SDI (MISO)
|
||||||
|
SPI2_CS_PIN = GPIO34 // CS
|
||||||
|
)
|
||||||
@@ -15,8 +15,8 @@ const (
|
|||||||
P09 Pin = 9
|
P09 Pin = 9
|
||||||
P10 Pin = 10
|
P10 Pin = 10
|
||||||
P11 Pin = 11
|
P11 Pin = 11
|
||||||
P12 Pin = 12
|
P12 Pin = 12 // peripherals: I2C0 SDA
|
||||||
P13 Pin = 13
|
P13 Pin = 13 // peripherals: I2C0 SCL
|
||||||
P14 Pin = 14
|
P14 Pin = 14
|
||||||
P15 Pin = 15
|
P15 Pin = 15
|
||||||
P16 Pin = 16
|
P16 Pin = 16
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user