mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-27 07:08:42 +00:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80c89809a9 | |||
| 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 |
+10
-8
@@ -92,16 +92,20 @@ commands:
|
||||
- /go/pkg/mod
|
||||
|
||||
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:
|
||||
- image: golang:1.22-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "15"
|
||||
resource_class: large
|
||||
test-llvm20-go124:
|
||||
test-newest:
|
||||
# This tests the latest supported LLVM version when linking against system
|
||||
# libraries.
|
||||
docker:
|
||||
- image: golang:1.24-bullseye
|
||||
- image: golang:1.25-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "20"
|
||||
@@ -110,8 +114,6 @@ jobs:
|
||||
workflows:
|
||||
test-all:
|
||||
jobs:
|
||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||
# least the smoke tests still pass.
|
||||
- test-llvm15-go122
|
||||
# This tests LLVM 20 support when linking against system libraries.
|
||||
- test-llvm20-go124
|
||||
- test-oldest
|
||||
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
|
||||
# - test-newest
|
||||
|
||||
@@ -16,36 +16,37 @@ jobs:
|
||||
name: build-macos
|
||||
strategy:
|
||||
matrix:
|
||||
# macos-13: amd64 (oldest supported version as of 18-10-2024)
|
||||
# macos-14: arm64 (oldest arm64 version)
|
||||
os: [macos-13, macos-14]
|
||||
# macos-14: arm64 (oldest supported version as of 18-11-2025)
|
||||
# macos-15-intel: amd64 (last intel version to be supported by github runners)
|
||||
# See https://github.com/actions/runner-images/issues/13046
|
||||
os: [macos-14, macos-15-intel]
|
||||
include:
|
||||
- os: macos-13
|
||||
goarch: amd64
|
||||
- os: macos-14
|
||||
goarch: arm64
|
||||
- os: macos-15-intel
|
||||
goarch: amd64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-${{ matrix.os }}-v1
|
||||
key: llvm-source-20-${{ matrix.os }}-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -70,7 +71,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-${{ matrix.os }}-v1
|
||||
key: llvm-build-20-${{ matrix.os }}-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -79,7 +80,7 @@ jobs:
|
||||
rm -rf llvm-project
|
||||
make llvm-source
|
||||
# install dependencies
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install ninja
|
||||
# build!
|
||||
make llvm-build
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
@@ -130,11 +131,11 @@ jobs:
|
||||
run: |
|
||||
brew install llvm@${{ matrix.version }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
sudo rm -rf /usr/local/share/boost
|
||||
df -h
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -66,45 +66,3 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Trigger Drivers repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger Bluetooth repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyFS repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyFont repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyDraw repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyTerm repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
|
||||
+18
-18
@@ -18,7 +18,7 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.24-alpine
|
||||
image: golang:1.25-alpine
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
@@ -26,12 +26,12 @@ jobs:
|
||||
# tar: needed for actions/cache@v4
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh make g++ ruby-dev
|
||||
run: apk add tar git openssh make g++ ruby-dev mold
|
||||
- name: Work around CVE-2022-24765
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-linux-alpine-v1
|
||||
key: llvm-source-20-linux-alpine-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-linux-alpine-v1
|
||||
key: llvm-build-20-linux-alpine-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -131,13 +131,13 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
@@ -179,9 +179,9 @@ jobs:
|
||||
simavr \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-linux-asserts-v1
|
||||
key: llvm-source-20-linux-asserts-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-linux-asserts-v1
|
||||
key: llvm-build-20-linux-asserts-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -284,7 +284,7 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Get TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
@@ -296,15 +296,15 @@ jobs:
|
||||
g++-${{ matrix.toolchain }} \
|
||||
libc6-dev-${{ matrix.libc }}-cross
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-linux-v1
|
||||
key: llvm-source-20-linux-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -329,7 +329,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-linux-${{ matrix.goarch }}-v3
|
||||
key: llvm-build-20-linux-${{ matrix.goarch }}-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
@@ -35,8 +35,8 @@ jobs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
tinygo/llvm-19
|
||||
ghcr.io/${{ github.repository_owner }}/llvm-19
|
||||
tinygo/llvm-20
|
||||
ghcr.io/${{ github.repository_owner }}/llvm-20
|
||||
tags: |
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
target: tinygo-llvm-build
|
||||
context: .
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
|
||||
run: sudo apt-get remove llvm-18
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Pull musl, bdwgc
|
||||
run: |
|
||||
git submodule update --init lib/musl lib/bdwgc
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-linux-nix-v1
|
||||
key: llvm-source-20-linux-nix-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-sizediff-v1
|
||||
key: llvm-source-20-sizediff-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: |
|
||||
scoop install ninja binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -39,15 +39,15 @@ jobs:
|
||||
shell: bash
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-19-windows-v1
|
||||
key: llvm-source-20-windows-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-windows-v1
|
||||
key: llvm-build-20-windows-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -143,11 +143,11 @@ jobs:
|
||||
run: |
|
||||
scoop install binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -173,11 +173,11 @@ jobs:
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -209,11 +209,11 @@ jobs:
|
||||
run: |
|
||||
scoop install binaryen && scoop install wasmtime@29.0.1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.25.5'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
+2
-2
@@ -16,13 +16,13 @@
|
||||
url = https://github.com/WebAssembly/wasi-libc
|
||||
[submodule "lib/picolibc"]
|
||||
path = lib/picolibc
|
||||
url = https://github.com/keith-packard/picolibc.git
|
||||
url = https://github.com/picolibc/picolibc.git
|
||||
[submodule "lib/stm32-svd"]
|
||||
path = lib/stm32-svd
|
||||
url = https://github.com/tinygo-org/stm32-svd
|
||||
[submodule "lib/musl"]
|
||||
path = lib/musl
|
||||
url = git://git.musl-libc.org/musl
|
||||
url = https://github.com/tinygo-org/musl-libc.git
|
||||
[submodule "lib/binaryen"]
|
||||
path = lib/binaryen
|
||||
url = https://github.com/WebAssembly/binaryen.git
|
||||
|
||||
+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
|
||||
---
|
||||
* **general**
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
# 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 && \
|
||||
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 \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/log/* \
|
||||
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
|
||||
|
||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||
# all the build tools etc).
|
||||
FROM golang:1.24 AS tinygo-compiler
|
||||
FROM golang:1.25 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
+49
-12
@@ -79,6 +79,26 @@ ifeq (1, $(STATIC))
|
||||
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
|
||||
endif
|
||||
|
||||
# Optimize the binary size for Linux.
|
||||
# These flags may work on other platforms, but have only been tested on Linux.
|
||||
ifeq ($(uname),Linux)
|
||||
HAS_MOLD := $(shell command -v ld.mold 2> /dev/null)
|
||||
HAS_LLD := $(shell command -v ld.lld 2> /dev/null)
|
||||
LLVM_CFLAGS := -ffunction-sections -fdata-sections -fvisibility=hidden
|
||||
LLVM_LDFLAGS := -Wl,--gc-sections
|
||||
ifneq ($(HAS_MOLD),)
|
||||
# Mold might be slightly faster.
|
||||
LLVM_LDFLAGS += -fuse-ld=mold -Wl,--icf=all
|
||||
else ifneq ($(HAS_LLD),)
|
||||
# LLD is more commonly available.
|
||||
LLVM_LDFLAGS += -fuse-ld=lld -Wl,--icf=all
|
||||
endif
|
||||
LLVM_OPTION += \
|
||||
-DCMAKE_C_FLAGS="$(LLVM_CFLAGS)" \
|
||||
-DCMAKE_CXX_FLAGS="$(LLVM_CFLAGS)"
|
||||
CGO_LDFLAGS += $(LLVM_LDFLAGS)
|
||||
endif
|
||||
|
||||
# Cross compiling support.
|
||||
ifneq ($(CROSS),)
|
||||
CC = $(CROSS)-gcc
|
||||
@@ -243,7 +263,7 @@ gen-device-renesas: build/gen-device-svd
|
||||
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
||||
|
||||
$(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
|
||||
|
||||
# Configure LLVM.
|
||||
@@ -460,11 +480,16 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
||||
TEST_IOFS := false
|
||||
endif
|
||||
|
||||
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
|
||||
TEST_ADDITIONAL_FLAGS ?=
|
||||
|
||||
# Test known-working standard library packages.
|
||||
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
||||
.PHONY: tinygo-test
|
||||
tinygo-test:
|
||||
$(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
|
||||
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
||||
@# For more details, see the comments on issue #3143.
|
||||
@@ -472,7 +497,7 @@ ifeq ($(TEST_IOFS),true)
|
||||
$(TINYGO) test -stack-size=6MB io/fs
|
||||
endif
|
||||
tinygo-test-fast:
|
||||
$(TINYGO) test $(TEST_PACKAGES_HOST)
|
||||
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST)
|
||||
tinygo-bench:
|
||||
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-fast:
|
||||
@@ -480,18 +505,18 @@ tinygo-bench-fast:
|
||||
|
||||
# Same thing, except for wasi rather than the current platform.
|
||||
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 -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:
|
||||
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 -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 -target=wasip2 $(TEST_PACKAGES_SLOW)
|
||||
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_SLOW)
|
||||
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=$(TINYGO) \
|
||||
@@ -517,7 +542,7 @@ tinygo-bench-wasip2-fast:
|
||||
|
||||
# Run tests on riscv-qemu since that one provides a large amount of memory.
|
||||
tinygo-test-baremetal:
|
||||
$(TINYGO) test -target riscv-qemu $(TEST_PACKAGES_BAREMETAL)
|
||||
$(TINYGO) test -target riscv-qemu $(TEST_SKIP_FLAG) $(TEST_PACKAGES_BAREMETAL)
|
||||
|
||||
# Test external packages in a large corpus.
|
||||
test-corpus:
|
||||
@@ -597,6 +622,8 @@ smoketest: testchdir
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
@@ -771,6 +798,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=gopher-arcade examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
||||
@@ -781,6 +810,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=metro-rp2350 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
@@ -884,6 +915,8 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
@@ -945,7 +978,7 @@ endif
|
||||
|
||||
|
||||
wasmtest:
|
||||
$(GO) test ./tests/wasm
|
||||
cd ./tests/wasm && $(GO) test .
|
||||
|
||||
build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
|
||||
@mkdir -p build/release/tinygo/bin
|
||||
@@ -1092,6 +1125,7 @@ endif
|
||||
tools:
|
||||
cd internal/tools && go generate -tags tools ./
|
||||
|
||||
LINTDIRS=src/os/ src/reflect/
|
||||
.PHONY: lint
|
||||
lint: tools ## Lint source tree
|
||||
revive -version
|
||||
@@ -1099,7 +1133,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.
|
||||
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
|
||||
# Use 'grep .' to get rid of stray blank line
|
||||
revive -config revive.toml compiler/... 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
|
||||
.PHONY: spell
|
||||
|
||||
+6
-3
@@ -30,7 +30,10 @@ var BoehmGC = Library{
|
||||
// Use a minimal environment.
|
||||
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
|
||||
"-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.
|
||||
// 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.
|
||||
"-DSTACK_NOT_SCANNED",
|
||||
"-DNO_PROC_STAT", // we scan the stack manually (don't read /proc/self/stat on Linux)
|
||||
"-DSTACKBOTTOM=0", // dummy value, we scan the stack manually
|
||||
|
||||
// Assertions can be enabled while debugging GC issues.
|
||||
//"-DGC_ASSERTIONS",
|
||||
@@ -63,7 +68,6 @@ var BoehmGC = Library{
|
||||
"blacklst.c",
|
||||
"dbg_mlc.c",
|
||||
"dyn_load.c",
|
||||
"finalize.c",
|
||||
"headers.c",
|
||||
"mach_dep.c",
|
||||
"malloc.c",
|
||||
@@ -71,7 +75,6 @@ var BoehmGC = Library{
|
||||
"mark_rts.c",
|
||||
"misc.c",
|
||||
"new_hblk.c",
|
||||
"obj_map.c",
|
||||
"os_dep.c",
|
||||
"reclaim.c",
|
||||
}
|
||||
|
||||
+2
-2
@@ -1042,11 +1042,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if err != nil {
|
||||
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
|
||||
// bootloader).
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err := makeESPFirmareImage(result.Executable, result.Binary, outputBinaryFormat)
|
||||
err := makeESPFirmwareImage(result.Executable, result.Binary, outputBinaryFormat)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func TestClangAttributes(t *testing.T) {
|
||||
"cortex-m4",
|
||||
"cortex-m7",
|
||||
"esp32c3",
|
||||
"esp32s3",
|
||||
"fe310",
|
||||
"gameboy-advance",
|
||||
"k210",
|
||||
|
||||
+13
-8
@@ -144,8 +144,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
.Default(llvm::DebugCompressionType::None);
|
||||
}
|
||||
|
||||
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
|
||||
Opts.SSE2AVX = Args.hasArg(OPT_msse2avx);
|
||||
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
|
||||
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
|
||||
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
|
||||
@@ -236,6 +234,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
Opts.EmitCompactUnwindNonCanonical =
|
||||
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
||||
Opts.Crel = Args.hasArg(OPT_crel);
|
||||
Opts.ImplicitMapsyms = Args.hasArg(OPT_mmapsyms_implicit);
|
||||
Opts.X86RelaxRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
|
||||
Opts.X86Sse2Avx = Args.hasArg(OPT_msse2avx);
|
||||
|
||||
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
||||
|
||||
@@ -294,8 +295,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
||||
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
|
||||
MCOptions.Crel = Opts.Crel;
|
||||
MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations;
|
||||
MCOptions.X86Sse2Avx = Opts.SSE2AVX;
|
||||
MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
|
||||
MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
|
||||
MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
|
||||
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
|
||||
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
||||
|
||||
@@ -343,10 +345,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||
std::unique_ptr<MCObjectFileInfo> MOFI(
|
||||
TheTarget->createMCObjectFileInfo(Ctx, PIC));
|
||||
if (Opts.DarwinTargetVariantTriple)
|
||||
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
|
||||
if (!Opts.DarwinTargetVariantSDKVersion.empty())
|
||||
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
|
||||
Ctx.setObjectFileInfo(MOFI.get());
|
||||
|
||||
if (Opts.GenDwarfForAssembly)
|
||||
@@ -428,6 +426,13 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
Str.reset(TheTarget->createMCObjectStreamer(
|
||||
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
|
||||
Str.get()->initSections(Opts.NoExecStack, *STI);
|
||||
if (T.isOSBinFormatMachO() && T.isOSDarwin()) {
|
||||
Triple *TVT = Opts.DarwinTargetVariantTriple
|
||||
? &*Opts.DarwinTargetVariantTriple
|
||||
: nullptr;
|
||||
Str->emitVersionForTarget(T, VersionTuple(), TVT,
|
||||
Opts.DarwinTargetVariantSDKVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
||||
|
||||
+10
-5
@@ -45,10 +45,6 @@ struct AssemblerInvocation {
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned GenDwarfForAssembly : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned RelaxELFRelocations : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned SSE2AVX : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned Dwarf64 : 1;
|
||||
unsigned DwarfVersion;
|
||||
std::string DwarfDebugFlags;
|
||||
@@ -117,6 +113,13 @@ struct AssemblerInvocation {
|
||||
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned Crel : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned ImplicitMapsyms : 1;
|
||||
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned X86RelaxRelocations : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned X86Sse2Avx : 1;
|
||||
|
||||
/// The name of the relocation model to use.
|
||||
std::string RelocationModel;
|
||||
@@ -148,7 +151,6 @@ public:
|
||||
ShowInst = 0;
|
||||
ShowEncoding = 0;
|
||||
RelaxAll = 0;
|
||||
SSE2AVX = 0;
|
||||
NoExecStack = 0;
|
||||
FatalWarnings = 0;
|
||||
NoWarn = 0;
|
||||
@@ -160,6 +162,9 @@ public:
|
||||
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
||||
EmitCompactUnwindNonCanonical = false;
|
||||
Crel = false;
|
||||
ImplicitMapsyms = 0;
|
||||
X86RelaxRelocations = 0;
|
||||
X86Sse2Avx = 0;
|
||||
}
|
||||
|
||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ bool tinygo_clang_driver(int argc, char **argv) {
|
||||
}
|
||||
|
||||
// Create the actual diagnostics engine.
|
||||
Clang->createDiagnostics();
|
||||
Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
|
||||
if (!Clang->hasDiagnostics()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+8
-5
@@ -26,17 +26,20 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
|
||||
// Version range supported by TinyGo.
|
||||
const minorMin = 19
|
||||
const minorMax = 24
|
||||
const minorMax = 25
|
||||
|
||||
// Check that we support this Go toolchain version.
|
||||
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||
|
||||
if options.GoCompatibility {
|
||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||
//
|
||||
@@ -31,7 +31,7 @@ type espImageSegment struct {
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
||||
// https://github.com/espressif/esptool/blob/master/esptool.py
|
||||
func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
func makeESPFirmwareImage(infile, outfile, format string) error {
|
||||
inf, err := elf.Open(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -100,11 +100,12 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
chip_id := map[string]uint16{
|
||||
"esp32": 0x0000,
|
||||
"esp32c3": 0x0005,
|
||||
"esp32s3": 0x0009,
|
||||
}[chip]
|
||||
|
||||
// Image header.
|
||||
switch chip {
|
||||
case "esp32", "esp32c3":
|
||||
case "esp32", "esp32c3", "esp32s3":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
||||
// Note: not adding a SHA256 hash as the binary is modified by
|
||||
|
||||
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4556, 280, 0, 2264},
|
||||
{"microbit", "examples/serial", 2920, 388, 8, 2272},
|
||||
{"wioterminal", "examples/pininterrupt", 7379, 1489, 116, 6912},
|
||||
{"hifive1b", "examples/echo", 3668, 280, 0, 2244},
|
||||
{"microbit", "examples/serial", 2694, 342, 8, 2248},
|
||||
{"wioterminal", "examples/pininterrupt", 6833, 1491, 120, 6888},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// 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.
|
||||
func (c *Config) MaxStackAlloc() uint64 {
|
||||
if c.StackSize() > 32*1024 {
|
||||
if c.StackSize() >= 16*1024 {
|
||||
return 1024
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ type Options struct {
|
||||
WITPackage string // pass through to wasm-tools component embed invocation
|
||||
WITWorld string // pass through to wasm-tools component embed -w option
|
||||
ExtLDFlags []string
|
||||
GoCompatibility bool // enable to check for Go version compatibility
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
|
||||
+1
-1
@@ -245,7 +245,7 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
|
||||
// current insert position.
|
||||
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
|
||||
b.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.
|
||||
b.CreateCondBr(assert, faultBlock, nextBlock)
|
||||
|
||||
@@ -32,6 +32,9 @@ const (
|
||||
// Whether this is a full or partial Go parameter (int, slice, etc).
|
||||
// The extra context parameter is not a Go parameter.
|
||||
paramIsGoParam = 1 << iota
|
||||
|
||||
// Whether this is a readonly parameter (for example, a string pointer).
|
||||
paramIsReadonly
|
||||
)
|
||||
|
||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
||||
@@ -167,6 +170,7 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
||||
continue
|
||||
}
|
||||
suffix := strconv.Itoa(i)
|
||||
isString := false
|
||||
if goType != nil {
|
||||
// Try to come up with a good suffix for this struct field,
|
||||
// depending on which Go type it's based on.
|
||||
@@ -183,12 +187,16 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
||||
suffix = []string{"r", "i"}[i]
|
||||
case types.String:
|
||||
suffix = []string{"data", "len"}[i]
|
||||
isString = true
|
||||
}
|
||||
case *types.Signature:
|
||||
suffix = []string{"context", "funcptr"}[i]
|
||||
}
|
||||
}
|
||||
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||
if isString {
|
||||
subInfos[0].flags |= paramIsReadonly
|
||||
}
|
||||
paramInfos = append(paramInfos, subInfos...)
|
||||
}
|
||||
return paramInfos
|
||||
|
||||
+47
-17
@@ -152,10 +152,12 @@ type builder struct {
|
||||
llvmFnType llvm.Type
|
||||
llvmFn llvm.Value
|
||||
info functionInfo
|
||||
locals map[ssa.Value]llvm.Value // local variables
|
||||
blockEntries map[*ssa.BasicBlock]llvm.BasicBlock // a *ssa.BasicBlock may be split up
|
||||
blockExits map[*ssa.BasicBlock]llvm.BasicBlock // these are the exit blocks
|
||||
locals map[ssa.Value]llvm.Value // local variables
|
||||
blockInfo []blockInfo
|
||||
currentBlock *ssa.BasicBlock
|
||||
currentBlockInfo *blockInfo
|
||||
tarjanStack []uint
|
||||
tarjanIndex uint
|
||||
phis []phiNode
|
||||
deferPtr llvm.Value
|
||||
deferFrame llvm.Value
|
||||
@@ -187,11 +189,22 @@ func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *bu
|
||||
info: c.getFunctionInfo(f),
|
||||
locals: make(map[ssa.Value]llvm.Value),
|
||||
dilocals: make(map[*types.Var]llvm.Metadata),
|
||||
blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
||||
blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
||||
}
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
// entry is the LLVM basic block corresponding to the start of this *ssa.Block.
|
||||
entry llvm.BasicBlock
|
||||
|
||||
// exit is the LLVM basic block corresponding to the end of this *ssa.Block.
|
||||
// It will be different than entry if any of the block's instructions contain internal branches.
|
||||
exit llvm.BasicBlock
|
||||
|
||||
// tarjan holds state for applying Tarjan's strongly connected components algorithm to the CFG.
|
||||
// This is used by defer.go to determine whether to stack- or heap-allocate defer data.
|
||||
tarjan tarjanNode
|
||||
}
|
||||
|
||||
type deferBuiltin struct {
|
||||
callName string
|
||||
pos token.Pos
|
||||
@@ -1220,14 +1233,29 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
||||
// intrinsic (like an atomic operation). Create the entry block
|
||||
// manually.
|
||||
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
||||
} else {
|
||||
for _, block := range b.fn.DomPreorder() {
|
||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||
b.blockEntries[block] = llvmBlock
|
||||
b.blockExits[block] = llvmBlock
|
||||
// Intrinsics may create internal branches (e.g. nil checks).
|
||||
// They will attempt to access b.currentBlockInfo to update the exit block.
|
||||
// Create some fake block info for them to access.
|
||||
blockInfo := []blockInfo{
|
||||
{
|
||||
entry: entryBlock,
|
||||
exit: entryBlock,
|
||||
},
|
||||
}
|
||||
b.blockInfo = blockInfo
|
||||
b.currentBlockInfo = &blockInfo[0]
|
||||
} else {
|
||||
blocks := b.fn.Blocks
|
||||
blockInfo := make([]blockInfo, len(blocks))
|
||||
for _, block := range b.fn.DomPreorder() {
|
||||
info := &blockInfo[block.Index]
|
||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||
info.entry = llvmBlock
|
||||
info.exit = llvmBlock
|
||||
}
|
||||
b.blockInfo = blockInfo
|
||||
// Normal functions have an entry block.
|
||||
entryBlock = b.blockEntries[b.fn.Blocks[0]]
|
||||
entryBlock = blockInfo[0].entry
|
||||
}
|
||||
b.SetInsertPointAtEnd(entryBlock)
|
||||
|
||||
@@ -1323,8 +1351,9 @@ func (b *builder) createFunction() {
|
||||
if b.DumpSSA {
|
||||
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
||||
}
|
||||
b.SetInsertPointAtEnd(b.blockEntries[block])
|
||||
b.currentBlock = block
|
||||
b.currentBlockInfo = &b.blockInfo[block.Index]
|
||||
b.SetInsertPointAtEnd(b.currentBlockInfo.entry)
|
||||
for _, instr := range block.Instrs {
|
||||
if instr, ok := instr.(*ssa.DebugRef); ok {
|
||||
if !b.Debug {
|
||||
@@ -1384,7 +1413,7 @@ func (b *builder) createFunction() {
|
||||
block := phi.ssa.Block()
|
||||
for i, edge := range phi.ssa.Edges {
|
||||
llvmVal := b.getValue(edge, getPos(phi.ssa))
|
||||
llvmBlock := b.blockExits[block.Preds[i]]
|
||||
llvmBlock := b.blockInfo[block.Preds[i].Index].exit
|
||||
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
||||
}
|
||||
}
|
||||
@@ -1498,11 +1527,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
case *ssa.If:
|
||||
cond := b.getValue(instr.Cond, getPos(instr))
|
||||
block := instr.Block()
|
||||
blockThen := b.blockEntries[block.Succs[0]]
|
||||
blockElse := b.blockEntries[block.Succs[1]]
|
||||
blockThen := b.blockInfo[block.Succs[0].Index].entry
|
||||
blockElse := b.blockInfo[block.Succs[1].Index].entry
|
||||
b.CreateCondBr(cond, blockThen, blockElse)
|
||||
case *ssa.Jump:
|
||||
blockJump := b.blockEntries[instr.Block().Succs[0]]
|
||||
blockJump := b.blockInfo[instr.Block().Succs[0].Index].entry
|
||||
b.CreateBr(blockJump)
|
||||
case *ssa.MapUpdate:
|
||||
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")
|
||||
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
||||
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")
|
||||
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
||||
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
||||
|
||||
+98
-28
@@ -100,7 +100,7 @@ func (b *builder) createLandingPad() {
|
||||
|
||||
// Continue at the 'recover' block, which returns to the parent in an
|
||||
// appropriate way.
|
||||
b.CreateBr(b.blockEntries[b.fn.Recover])
|
||||
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
|
||||
}
|
||||
|
||||
// Create a checkpoint (similar to setjmp). This emits inline assembly that
|
||||
@@ -234,41 +234,108 @@ func (b *builder) createInvokeCheckpoint() {
|
||||
continueBB := b.insertBasicBlock("")
|
||||
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
||||
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.
|
||||
func isInLoop(start *ssa.BasicBlock) bool {
|
||||
// Use a breadth-first search to scan backwards through the block graph.
|
||||
queue := []*ssa.BasicBlock{start}
|
||||
checked := map[*ssa.BasicBlock]struct{}{}
|
||||
// isInLoop checks if there is a path from the current block to itself.
|
||||
// Use Tarjan's strongly connected components algorithm to search for cycles.
|
||||
// A one-node SCC is a cycle iff there is an edge from the node to itself.
|
||||
// A multi-node SCC is always a cycle.
|
||||
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
func (b *builder) isInLoop() bool {
|
||||
if b.currentBlockInfo.tarjan.lowLink == 0 {
|
||||
b.strongConnect(b.currentBlock)
|
||||
}
|
||||
return b.currentBlockInfo.tarjan.cyclic
|
||||
}
|
||||
|
||||
for len(queue) > 0 {
|
||||
// pop a block off of the queue
|
||||
block := queue[len(queue)-1]
|
||||
queue = queue[:len(queue)-1]
|
||||
func (b *builder) strongConnect(block *ssa.BasicBlock) {
|
||||
// Assign a new index.
|
||||
// Indices start from 1 so that 0 can be used as a sentinel.
|
||||
assignedIndex := b.tarjanIndex + 1
|
||||
b.tarjanIndex = assignedIndex
|
||||
|
||||
// Search through predecessors.
|
||||
// Searching backwards means that this is pretty fast when the block is close to the start of the function.
|
||||
// Defers are often placed near the start of the function.
|
||||
for _, pred := range block.Preds {
|
||||
if pred == start {
|
||||
// cycle found
|
||||
return true
|
||||
}
|
||||
// Apply the new index.
|
||||
blockIndex := block.Index
|
||||
node := &b.blockInfo[blockIndex].tarjan
|
||||
node.lowLink = assignedIndex
|
||||
|
||||
if _, ok := checked[pred]; ok {
|
||||
// block already checked
|
||||
continue
|
||||
}
|
||||
// Push the node onto the stack.
|
||||
node.onStack = true
|
||||
b.tarjanStack = append(b.tarjanStack, uint(blockIndex))
|
||||
|
||||
// add to queue and checked map
|
||||
queue = append(queue, pred)
|
||||
checked[pred] = struct{}{}
|
||||
// Process the successors.
|
||||
for _, successor := range block.Succs {
|
||||
// Look up the successor's state.
|
||||
successorIndex := successor.Index
|
||||
if successorIndex == blockIndex {
|
||||
// Handle a self-cycle specially.
|
||||
node.cyclic = true
|
||||
continue
|
||||
}
|
||||
successorNode := &b.blockInfo[successorIndex].tarjan
|
||||
|
||||
switch {
|
||||
case successorNode.lowLink == 0:
|
||||
// This node has not yet been visisted.
|
||||
b.strongConnect(successor)
|
||||
|
||||
case !successorNode.onStack:
|
||||
// This node has been visited, but is in a different SCC.
|
||||
// Ignore it, and do not update lowLink.
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the lowLink index.
|
||||
// This always uses the min-of-lowlink instead of using index in the on-stack case.
|
||||
// This is done for two reasons:
|
||||
// 1. The lowLink update can be shared between the new-node and on-stack cases.
|
||||
// 2. The assigned index does not need to be saved - it is only needed for root node detection.
|
||||
if successorNode.lowLink < node.lowLink {
|
||||
node.lowLink = successorNode.lowLink
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -410,7 +477,10 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
|
||||
// Put this struct in an allocation.
|
||||
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.
|
||||
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
|
||||
} else {
|
||||
|
||||
@@ -38,10 +38,10 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
||||
// provided immediately. For example:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// "str {value}, [{result}]",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// "value": 1,
|
||||
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||
// })
|
||||
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||
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()
|
||||
okBlock := b.insertBasicBlock("typeassert.ok")
|
||||
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)
|
||||
|
||||
// Retrieve the value from the interface if the type assert was
|
||||
|
||||
@@ -27,6 +27,8 @@ func (b *builder) defineIntrinsicFunction() {
|
||||
b.createStackSaveImpl()
|
||||
case name == "runtime.KeepAlive":
|
||||
b.createKeepAliveImpl()
|
||||
case name == "machine.keepAliveNoEscape":
|
||||
b.createMachineKeepAliveImpl()
|
||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||
b.createVolatileLoad()
|
||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||
@@ -121,6 +123,43 @@ func (b *builder) createKeepAliveImpl() {
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
|
||||
// currently only supports pointer types.
|
||||
func (b *builder) createAbiEscapeImpl() {
|
||||
b.createFunctionStart(true)
|
||||
|
||||
// The first parameter is assumed to be a pointer. This is checked at the
|
||||
// call site of createAbiEscapeImpl.
|
||||
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
|
||||
// Create an equivalent of the following C code, which is basically just a
|
||||
// nop but ensures the pointerValue is kept alive:
|
||||
//
|
||||
// __asm__ __volatile__("" : : "r"(pointerValue))
|
||||
//
|
||||
// It should be portable to basically everything as the "r" register type
|
||||
// exists basically everywhere.
|
||||
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
|
||||
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
|
||||
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||
|
||||
b.CreateRet(result)
|
||||
}
|
||||
|
||||
// Implement machine.keepAliveNoEscape, which makes sure the compiler keeps the
|
||||
// pointer parameter alive until this point (for GC).
|
||||
func (b *builder) createMachineKeepAliveImpl() {
|
||||
b.createFunctionStart(true)
|
||||
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
|
||||
// See createKeepAliveImpl for details.
|
||||
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
|
||||
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
|
||||
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
var mathToLLVMMapping = map[string]string{
|
||||
"math.Ceil": "llvm.ceil.f64",
|
||||
"math.Exp": "llvm.exp.f64",
|
||||
|
||||
@@ -218,7 +218,7 @@ func Version() int {
|
||||
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.
|
||||
func ByteOrder(target string) binary.ByteOrder {
|
||||
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 {
|
||||
switch keyType := keyType.Underlying().(type) {
|
||||
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
|
||||
case *types.Pointer:
|
||||
return true
|
||||
|
||||
+39
-4
@@ -142,6 +142,11 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
|
||||
llvmFn.AddAttributeAtIndex(i+1, nocapture)
|
||||
}
|
||||
if paramInfo.flags¶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
|
||||
@@ -154,6 +159,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
|
||||
case "internal/abi.NoEscape":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "machine.keepAliveNoEscape", "machine.unsafeNoEscape":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.alloc":
|
||||
// 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.
|
||||
@@ -253,6 +260,23 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
|
||||
// The exception is the package initializer, which does appear in the
|
||||
// *ssa.Package members and so shouldn't be created here.
|
||||
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
|
||||
if origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
|
||||
// This is a special implementation or internal/abi.Escape, which
|
||||
// can only really be implemented in the compiler.
|
||||
// For simplicity we'll only implement pointer parameters for now.
|
||||
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
|
||||
irbuilder := c.ctx.NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
b := newBuilder(c, irbuilder, fn)
|
||||
b.createAbiEscapeImpl()
|
||||
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
llvmFn.SetUnnamedAddr(true)
|
||||
}
|
||||
// If the parameter is not of a pointer type, it will be left
|
||||
// unimplemented. This will result in a linker error if the function
|
||||
// is really called, making it clear it needs to be implemented.
|
||||
return
|
||||
}
|
||||
if len(fn.Blocks) == 0 {
|
||||
c.addError(fn.Pos(), "missing function body")
|
||||
return
|
||||
@@ -613,7 +637,7 @@ func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
|
||||
// linkName is equal to .RelString(nil) on a global and extern is false, but for
|
||||
// some symbols this is different (due to //go:extern for example).
|
||||
type globalInfo struct {
|
||||
linkName string // go:extern
|
||||
linkName string // go:extern, go:linkname
|
||||
extern bool // go:extern
|
||||
align int // go:align
|
||||
section string // go:section
|
||||
@@ -698,14 +722,14 @@ func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
|
||||
// Check for //go: pragmas, which may change the link name (among others).
|
||||
doc := c.astComments[info.linkName]
|
||||
if doc != nil {
|
||||
info.parsePragmas(doc)
|
||||
info.parsePragmas(doc, c, g)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// Parse //go: pragma comments from the source. In particular, it parses the
|
||||
// //go:extern pragma on globals.
|
||||
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
||||
// //go:extern and //go:linkname pragmas on globals.
|
||||
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext, g *ssa.Global) {
|
||||
for _, comment := range doc.List {
|
||||
if !strings.HasPrefix(comment.Text, "//go:") {
|
||||
continue
|
||||
@@ -726,6 +750,17 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
||||
if len(parts) == 2 {
|
||||
info.section = parts[1]
|
||||
}
|
||||
case "//go:linkname":
|
||||
if len(parts) != 3 || parts[1] != g.Name() {
|
||||
continue
|
||||
}
|
||||
// Only enable go:linkname when the package imports "unsafe".
|
||||
// This is a slightly looser requirement than what gc uses: gc
|
||||
// requires the file to import "unsafe", not the package as a
|
||||
// whole.
|
||||
if hasUnsafeImport(g.Pkg.Pkg) {
|
||||
info.linkName = parts[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,14 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||
if arch := b.archFamily(); arch != "arm" {
|
||||
// Some targets pretend to be linux/arm for compatibility but aren't
|
||||
// actually such a system. Make sure we emit an error instead of
|
||||
// creating inline assembly that will fail to compile.
|
||||
// See: https://github.com/tinygo-org/tinygo/issues/4959
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "system calls are not supported: target emulates a linux/arm system on "+arch)
|
||||
}
|
||||
|
||||
// Implement the EABI system call convention for Linux.
|
||||
// Source: syscall(2) man page.
|
||||
args := []llvm.Value{}
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'basic.go'
|
||||
source_filename = "basic.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
%main.kv = type { float, i32, i32, i32 }
|
||||
@@ -206,7 +206,7 @@ entry:
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+7
-7
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
%runtime.channelOp = type { ptr, ptr, i32, ptr }
|
||||
@@ -82,11 +82,11 @@ entry:
|
||||
store i32 1, ptr %select.send.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
||||
store ptr %ch1, ptr %select.states.alloca, align 4
|
||||
%select.states.alloca.repack1 = getelementptr inbounds 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
|
||||
%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
|
||||
%.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
|
||||
%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)
|
||||
@@ -107,8 +107,8 @@ select.body: ; preds = %select.next
|
||||
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
+242
-7
@@ -27,7 +27,7 @@ entry:
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack15 = getelementptr inbounds 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 %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
|
||||
@@ -51,7 +51,7 @@ rundefers.loophead: ; preds = %3, %rundefers.block
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds 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
|
||||
store ptr %stack.next, ptr %deferPtr, 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
|
||||
|
||||
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
|
||||
store ptr %stack.next9, ptr %deferPtr, align 4
|
||||
%callback11 = load i32, ptr %4, align 4
|
||||
@@ -144,11 +144,11 @@ entry:
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack22 = getelementptr inbounds 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 %defer.alloca, ptr %deferPtr, 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.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
|
||||
@@ -172,7 +172,7 @@ rundefers.loophead: ; preds = %4, %3, %rundefers.b
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds 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
|
||||
store ptr %stack.next, ptr %deferPtr, 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
|
||||
|
||||
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
|
||||
store ptr %stack.next13, ptr %deferPtr, align 4
|
||||
%callback15 = load i32, ptr %5, align 4
|
||||
@@ -270,6 +270,241 @@ entry:
|
||||
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 #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" }
|
||||
|
||||
Vendored
+20
@@ -18,3 +18,23 @@ func deferMultiple() {
|
||||
}()
|
||||
external()
|
||||
}
|
||||
|
||||
func deferInfiniteLoop() {
|
||||
for {
|
||||
defer print(8)
|
||||
}
|
||||
}
|
||||
|
||||
func deferLoop() {
|
||||
for i := 0; i < 10; i++ {
|
||||
defer print(i)
|
||||
}
|
||||
}
|
||||
|
||||
func deferBetweenLoops() {
|
||||
for i := 0; i < 10; i++ {
|
||||
}
|
||||
defer print(1)
|
||||
for i := 0; i < 10; i++ {
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
@@ -93,6 +93,6 @@ entry:
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
@@ -44,7 +44,7 @@ entry:
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+11
-11
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'gc.go'
|
||||
source_filename = "gc.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
@@ -105,18 +105,18 @@ entry:
|
||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice, ptr @main.slice1, align 4
|
||||
store i32 5, ptr getelementptr inbounds (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 4), 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
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice1, ptr @main.slice2, align 4
|
||||
store i32 5, ptr getelementptr inbounds (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 4), 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
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice3, ptr @main.slice3, align 4
|
||||
store i32 5, ptr getelementptr inbounds (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 4), align 4
|
||||
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 8), align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ entry:
|
||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store double %v.r, ptr %0, align 8
|
||||
%.repack1 = getelementptr inbounds i8, ptr %0, i32 8
|
||||
%.repack1 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
store double %v.i, ptr %.repack1, align 8
|
||||
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
|
||||
@@ -135,7 +135,7 @@ entry:
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+5
-5
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'go1.20.go'
|
||||
source_filename = "go1.20.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
@@ -50,14 +50,14 @@ unsafe.String.throw: ; preds = %entry
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
|
||||
; 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:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+9
-9
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'go1.21.go'
|
||||
source_filename = "go1.21.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
@@ -77,7 +77,7 @@ entry:
|
||||
}
|
||||
|
||||
; 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:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
@@ -86,12 +86,12 @@ entry:
|
||||
%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
|
||||
%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
|
||||
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
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
@@ -116,7 +116,7 @@ entry:
|
||||
}
|
||||
|
||||
; 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:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
@@ -125,7 +125,7 @@ entry:
|
||||
%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
|
||||
%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
|
||||
ret %runtime._string %5
|
||||
}
|
||||
@@ -171,9 +171,9 @@ 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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
||||
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
+12
-12
@@ -65,7 +65,7 @@ entry:
|
||||
store i32 3, ptr %n, align 4
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %n, ptr %1, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
@@ -87,7 +87,7 @@ entry:
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
|
||||
ret void
|
||||
@@ -104,9 +104,9 @@ define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %co
|
||||
entry:
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 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
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
@@ -117,9 +117,9 @@ entry:
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||
entry:
|
||||
%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
|
||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
ret void
|
||||
@@ -154,11 +154,11 @@ define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value,
|
||||
entry:
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 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
|
||||
%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
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
@@ -171,11 +171,11 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
||||
entry:
|
||||
%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
|
||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%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
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
ret void
|
||||
|
||||
+22
-22
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
@@ -72,7 +72,7 @@ entry:
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %n, ptr %1, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
%2 = load i32, ptr %n, align 4
|
||||
@@ -93,7 +93,7 @@ entry:
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
@@ -113,9 +113,9 @@ entry:
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 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
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
ret void
|
||||
@@ -125,9 +125,9 @@ entry:
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||
entry:
|
||||
%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
|
||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
@@ -165,11 +165,11 @@ entry:
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds i8, ptr %0, i32 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 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
|
||||
%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
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
ret void
|
||||
@@ -181,24 +181,24 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
||||
entry:
|
||||
%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
|
||||
%4 = getelementptr inbounds i8, ptr %0, i32 8
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%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
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { 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,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #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,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
|
||||
Vendored
+8
-8
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'interface.go'
|
||||
source_filename = "interface.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
@@ -130,11 +130,11 @@ entry:
|
||||
|
||||
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 #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
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 }
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
@@ -44,7 +44,7 @@ entry:
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+11
-11
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'pragma.go'
|
||||
source_filename = "pragma.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-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"
|
||||
|
||||
@extern_global = external global [0 x i8], align 1
|
||||
@@ -93,13 +93,13 @@ entry:
|
||||
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 #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { 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,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
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
+9
-9
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
@@ -51,11 +51,11 @@ entry:
|
||||
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store i32 1, ptr %varargs, align 4
|
||||
%0 = getelementptr inbounds i8, ptr %varargs, i32 4
|
||||
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 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
|
||||
%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) #3
|
||||
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
|
||||
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
|
||||
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
|
||||
@@ -66,13 +66,13 @@ entry:
|
||||
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
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr 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) #3
|
||||
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
|
||||
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
|
||||
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
|
||||
@@ -322,7 +322,7 @@ unsafe.Slice.throw: ; preds = %entry
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+14
-14
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
@@ -31,13 +31,13 @@ entry:
|
||||
}
|
||||
|
||||
; 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:
|
||||
ret i32 %s.len
|
||||
}
|
||||
|
||||
; 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:
|
||||
%.not = icmp ult i32 %index, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -55,16 +55,16 @@ lookup.throw: ; preds = %entry
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
|
||||
; 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:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #1
|
||||
|
||||
; 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:
|
||||
%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
|
||||
@@ -72,23 +72,23 @@ entry:
|
||||
}
|
||||
|
||||
; 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:
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
|
||||
|
||||
; 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:
|
||||
%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
|
||||
|
||||
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
|
||||
ret i8 %2
|
||||
|
||||
@@ -97,7 +97,7 @@ lookup.throw: ; preds = %entry
|
||||
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 #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 #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+19
-19
@@ -1,6 +1,6 @@
|
||||
; ModuleID = '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"
|
||||
|
||||
%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 12, ptr nonnull %hashmap.key)
|
||||
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
|
||||
%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
|
||||
%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)
|
||||
@@ -60,9 +60,9 @@ entry:
|
||||
store i32 5, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||
%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
|
||||
%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.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)
|
||||
@@ -81,16 +81,16 @@ entry:
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||
%hashmap.key.repack1 = getelementptr inbounds 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
|
||||
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
|
||||
%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
|
||||
%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
|
||||
%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
|
||||
%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)
|
||||
@@ -109,16 +109,16 @@ entry:
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||
%hashmap.key.repack1 = getelementptr inbounds 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
|
||||
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
|
||||
%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
|
||||
%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
|
||||
%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.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)
|
||||
@@ -132,9 +132,9 @@ entry:
|
||||
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 #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { 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 #5 = { nounwind }
|
||||
|
||||
@@ -5,8 +5,6 @@ go 1.22.0
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
||||
github.com/chromedp/chromedp v0.7.6
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||
@@ -24,13 +22,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/chromedp/sysutil v1.0.0 // 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/stretchr/testify v1.8.4 // 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/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/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
|
||||
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
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/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/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/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/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
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-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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-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-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.39.0-dev"
|
||||
const version = "0.40.1"
|
||||
|
||||
// Return TinyGo version, either in the form 0.30.0 or as a development version
|
||||
// (like 0.30.0-dev-abcd012).
|
||||
|
||||
@@ -577,7 +577,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// runtime instead of at compile time. But we need to
|
||||
// revert any changes made by the call first.
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Err)
|
||||
fmt.Fprintln(os.Stderr, indent+"!! revert because of error:", callErr.Error())
|
||||
}
|
||||
callMem.revert()
|
||||
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.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
||||
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
|
||||
@main.negativeGEP = global ptr getelementptr inbounds nuw (i8, ptr @main.negativeGEP, i64 2)
|
||||
|
||||
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
|
||||
@pointerTagResult = local_unnamed_addr global i64 2
|
||||
@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 {
|
||||
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 {
|
||||
return true, nil
|
||||
// Return the compiler error, if there is one.
|
||||
return true, err
|
||||
}
|
||||
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
@@ -339,8 +340,17 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
|
||||
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.
|
||||
func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -389,13 +399,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if !options.Work {
|
||||
defer os.RemoveAll(tmpdir)
|
||||
}
|
||||
|
||||
// Validate output format before building
|
||||
if outpath != "" {
|
||||
if err := validateOutputFormat(outpath, fileExt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Build the binary.
|
||||
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
|
||||
if err != nil {
|
||||
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?
|
||||
if config.Target.PortReset == "true" && flashMethod != "openocd" {
|
||||
port, err := getDefaultPort(port, config.Target.SerialPort)
|
||||
@@ -1297,6 +1318,11 @@ extension at all.`
|
||||
(https://tinygo.org/docs/reference/microcontrollers/).
|
||||
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:
|
||||
Start the serial monitor (see below) immediately after
|
||||
flashing. However, some microcontrollers need a split second
|
||||
@@ -1609,6 +1635,7 @@ func main() {
|
||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||
monitor := flag.Bool("monitor", false, "enable 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.
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -1686,6 +1713,16 @@ func main() {
|
||||
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{
|
||||
GOOS: goenv.Get("GOOS"),
|
||||
GOARCH: goenv.Get("GOARCH"),
|
||||
@@ -1722,6 +1759,7 @@ func main() {
|
||||
Timeout: *timeout,
|
||||
WITPackage: witPackage,
|
||||
WITWorld: witWorld,
|
||||
GoCompatibility: *gocompatibility,
|
||||
}
|
||||
if *printCommands {
|
||||
options.PrintCommands = printCommand
|
||||
@@ -1778,7 +1816,7 @@ func main() {
|
||||
case "flash", "gdb", "lldb":
|
||||
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||
if command == "flash" {
|
||||
err := Flash(pkgName, *port, options)
|
||||
err := Flash(pkgName, *port, outpath, options)
|
||||
printBuildOutput(err, *flagJSON)
|
||||
} else {
|
||||
if !options.Debug {
|
||||
@@ -1864,6 +1902,7 @@ func main() {
|
||||
wd = ""
|
||||
}
|
||||
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
|
||||
os.Exit(1)
|
||||
}
|
||||
if !passed {
|
||||
select {
|
||||
|
||||
+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:
|
||||
// https://wiki.segger.com/RTT
|
||||
|
||||
// Try to find the "machine.rttSerialInstance" symbol, which is the RTT
|
||||
// control block.
|
||||
// Try to find the "_SEGGER_RTT" symbol (machine.rttSerialInstance)
|
||||
// symbol, which is the RTT control block.
|
||||
file, err := elf.Open(executable)
|
||||
if err != nil {
|
||||
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
|
||||
for _, symbol := range symbols {
|
||||
if symbol.Name == "machine.rttSerialInstance" {
|
||||
if symbol.Name == "_SEGGER_RTT" {
|
||||
address = symbol.Value
|
||||
break
|
||||
}
|
||||
|
||||
@@ -63,6 +63,10 @@ func SecCertificateCopyData(cert CFRef) ([]byte, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func SecTrustCopyCertificateChain(trustObj CFRef) (CFRef, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ func Asm(asm string)
|
||||
// recognizes template values in the form {name}, like so:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// "str {value}, [{result}]",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// "value": 1,
|
||||
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||
// })
|
||||
//
|
||||
// You can use {} in the asm string (which expands to a register) to set the
|
||||
|
||||
@@ -1,29 +1,6 @@
|
||||
.syntax unified
|
||||
.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.
|
||||
// At some point, this should be replaced by inline assembly.
|
||||
.section .text.SemihostingCall
|
||||
|
||||
@@ -10,10 +10,10 @@ func Asm(asm string)
|
||||
// recognizes template values in the form {name}, like so:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// "str {value}, [{result}]",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// "value": 1,
|
||||
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||
// })
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// "str {value}, [{result}]",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// "value": 1,
|
||||
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||
// })
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "st {value}, {result}",
|
||||
// "st {value}, [{result}]",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// "value": 1,
|
||||
// "result": uintptr(unsafe.Pointer(&dest)),
|
||||
// })
|
||||
//
|
||||
// You can use {} in the asm string (which expands to a register) to set the
|
||||
|
||||
@@ -8,3 +8,10 @@ import "unsafe"
|
||||
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||
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)")
|
||||
}
|
||||
|
||||
@@ -1745,7 +1745,7 @@ func memzero(ptr unsafe.Pointer, size uintptr)
|
||||
func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//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
|
||||
@@ -1810,7 +1810,7 @@ func buflen(v Value) (unsafe.Pointer, uintptr) {
|
||||
}
|
||||
|
||||
//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
|
||||
func extendSlice(v Value, n int) sliceHeader {
|
||||
@@ -1823,7 +1823,10 @@ func extendSlice(v Value, n int) sliceHeader {
|
||||
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{
|
||||
data: nbuf,
|
||||
@@ -1862,8 +1865,10 @@ func AppendSlice(s, t Value) Value {
|
||||
}
|
||||
sSlice := (*sliceHeader)(s.value)
|
||||
tSlice := (*sliceHeader)(t.value)
|
||||
elemSize := s.typecode.elem().Size()
|
||||
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize)
|
||||
elem := s.typecode.elem()
|
||||
elemSize := elem.Size()
|
||||
elemLayout := elem.gcLayout()
|
||||
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize, elemLayout)
|
||||
result := &sliceHeader{
|
||||
data: ptr,
|
||||
len: len,
|
||||
|
||||
@@ -108,6 +108,10 @@ func (*stackState) unwind()
|
||||
func (t *Task) Resume() {
|
||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||
prevTask := currentTask
|
||||
if prevTask == nil {
|
||||
// Save the system stack pointer.
|
||||
saveStackPointer()
|
||||
}
|
||||
t.gcData.swap()
|
||||
currentTask = t
|
||||
if !t.state.launched {
|
||||
@@ -123,6 +127,9 @@ func (t *Task) Resume() {
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname saveStackPointer runtime.saveStackPointer
|
||||
func saveStackPointer()
|
||||
|
||||
//export tinygo_rewind
|
||||
func (*state) rewind()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build scheduler.tasks && esp32
|
||||
//go:build scheduler.tasks && (esp32 || esp32s3)
|
||||
|
||||
package task
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ void tinygo_task_init(void *mainTask, pthread_t *thread, int *numCPU, void *cont
|
||||
// Using pthread_kill, we can still send the signal to a specific thread.
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_handler = tinygo_task_gc_pause;
|
||||
act.sa_flags = SA_RESTART;
|
||||
sigaction(taskPauseSignal, &act, NULL);
|
||||
|
||||
// Obtain the number of CPUs available on program start (for NumCPU).
|
||||
@@ -100,7 +101,7 @@ static void* start_wrapper(void *arg) {
|
||||
};
|
||||
|
||||
// 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.
|
||||
if (sizeof(pthread_t) != sizeof(void*)) {
|
||||
__builtin_trap();
|
||||
@@ -117,13 +118,23 @@ int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, u
|
||||
#else
|
||||
sem_init(&state.startlock, 0, 0);
|
||||
#endif
|
||||
int result = pthread_create(thread, NULL, &start_wrapper, &state);
|
||||
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.
|
||||
#if __APPLE__
|
||||
dispatch_semaphore_wait(state.startlock, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(state.startlock);
|
||||
#else
|
||||
sem_wait(&state.startlock);
|
||||
sem_destroy(&state.startlock);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
|
||||
@@ -23,16 +23,15 @@ type state struct {
|
||||
// is needed to be able to scan the stack.
|
||||
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.
|
||||
QueueNext *Task
|
||||
|
||||
// Semaphore to pause/resume the thread atomically.
|
||||
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.
|
||||
@@ -96,6 +95,9 @@ func (t *Task) Resume() {
|
||||
t.state.pauseSem.Post()
|
||||
}
|
||||
|
||||
// otherGoroutines is the total number of live goroutines minus one.
|
||||
var otherGoroutines uint32
|
||||
|
||||
// Start a new OS thread.
|
||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||
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
|
||||
// are not fully started yet.
|
||||
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 {
|
||||
runtimePanic("could not start thread")
|
||||
}
|
||||
t.state.QueueNext = activeTasks
|
||||
activeTasks = t
|
||||
otherGoroutines++
|
||||
activeTaskLock.Unlock()
|
||||
}
|
||||
|
||||
@@ -135,6 +138,7 @@ func taskExited(t *Task) {
|
||||
break
|
||||
}
|
||||
}
|
||||
otherGoroutines--
|
||||
activeTaskLock.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
@@ -143,9 +147,42 @@ func taskExited(t *Task) {
|
||||
}
|
||||
}
|
||||
|
||||
// Futex to wait on until all tasks have finished scanning the stack.
|
||||
// This is basically a sync.WaitGroup.
|
||||
var scanDoneFutex Futex
|
||||
// scanWaitGroup is used to wait on until all threads have finished the current state transition.
|
||||
var scanWaitGroup waitGroup
|
||||
|
||||
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
|
||||
// needs to be done in the tasks package.
|
||||
@@ -155,65 +192,71 @@ var scanDoneFutex Futex
|
||||
func GCStopWorldAndScan() {
|
||||
current := Current()
|
||||
|
||||
// Don't allow new goroutines to be started while pausing/resuming threads
|
||||
// in the stop-the-world phase.
|
||||
activeTaskLock.Lock()
|
||||
// NOTE: This does not need to be atomic.
|
||||
if gcState.Load() == gcStateResumed {
|
||||
// Don't allow new goroutines to be started while pausing/resuming threads
|
||||
// in the stop-the-world phase.
|
||||
activeTaskLock.Lock()
|
||||
|
||||
// Pause all other threads.
|
||||
numOtherThreads := uint32(0)
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
numOtherThreads++
|
||||
tinygo_task_send_gc_signal(t.state.thread)
|
||||
// Wait for threads to finish resuming.
|
||||
scanWaitGroup.wait()
|
||||
|
||||
// Change the gc state to stopped.
|
||||
// NOTE: This does not need to be atomic.
|
||||
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.
|
||||
// This is the equivalent of doing an initial wg.Add(numOtherThreads).
|
||||
scanDoneFutex.Store(numOtherThreads)
|
||||
// Scan other thread stacks.
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
markRoots(t.state.stackBottom, t.state.stackTop)
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the current stack, and all current registers.
|
||||
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).
|
||||
gcScanGlobals()
|
||||
}
|
||||
|
||||
// After the GC is done scanning, resume all other threads.
|
||||
//
|
||||
// This must only be called after a GCStopWorldAndScan call.
|
||||
func GCResumeWorld() {
|
||||
current := Current()
|
||||
|
||||
// Wake each paused thread for the second time, so they will resume normal
|
||||
// operation.
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
t.state.gcSem.Post()
|
||||
}
|
||||
// NOTE: This does not need to be atomic.
|
||||
if gcState.Load() == gcStateResumed {
|
||||
// This is already resumed.
|
||||
return
|
||||
}
|
||||
|
||||
// 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.
|
||||
activeTaskLock.Unlock()
|
||||
}
|
||||
|
||||
//go:linkname markRoots runtime.markRoots
|
||||
func markRoots(start, end uintptr)
|
||||
|
||||
// Scan globals, implemented in the runtime package.
|
||||
func gcScanGlobals()
|
||||
|
||||
@@ -221,34 +264,27 @@ var stackScanLock PMutex
|
||||
|
||||
//export tinygo_task_gc_pause
|
||||
func tingyo_task_gc_pause(sig int32) {
|
||||
// Wait until we get the signal to start scanning the stack.
|
||||
Current().state.gcSem.Wait()
|
||||
// Write the entrty stack pointer to the state.
|
||||
Current().state.stackBottom = uintptr(stacksave())
|
||||
|
||||
// Scan the thread stack.
|
||||
// Only scan a single thread stack at a time, because the GC marking phase
|
||||
// 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()
|
||||
// Notify the GC that we are stopped.
|
||||
scanWaitGroup.done()
|
||||
|
||||
// Equivalent of wg.Done(): subtract one from the futex and if the result is
|
||||
// 0 (meaning we were the last in the waitgroup), wake the waiting thread.
|
||||
n := uint32(1)
|
||||
if scanDoneFutex.Add(-n) == 0 {
|
||||
scanDoneFutex.Wake()
|
||||
// Wait for the GC to resume.
|
||||
for gcState.Load() == gcStateStopped {
|
||||
gcState.Wait(gcStateStopped)
|
||||
}
|
||||
|
||||
// Wait until we get the signal we can resume normally (after the mark phase
|
||||
// has finished).
|
||||
Current().state.gcSem.Wait()
|
||||
// Notify the GC that we have resumed.
|
||||
scanWaitGroup.done()
|
||||
}
|
||||
|
||||
//go:export tinygo_scanCurrentStack
|
||||
func scanCurrentStack()
|
||||
|
||||
//go:linkname stacksave runtime.stacksave
|
||||
func stacksave() unsafe.Pointer
|
||||
|
||||
// Return the highest address of the current stack.
|
||||
func StackTop() uintptr {
|
||||
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.
|
||||
//
|
||||
//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.
|
||||
//
|
||||
|
||||
@@ -15,8 +15,8 @@ const (
|
||||
P09 Pin = 9
|
||||
P10 Pin = 10
|
||||
P11 Pin = 11
|
||||
P12 Pin = 12
|
||||
P13 Pin = 13
|
||||
P12 Pin = 12 // peripherals: I2C0 SDA
|
||||
P13 Pin = 13 // peripherals: I2C0 SCL
|
||||
P14 Pin = 14
|
||||
P15 Pin = 15
|
||||
P16 Pin = 16
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//go:build gopher_arcade
|
||||
|
||||
package machine
|
||||
|
||||
// Return the current CPU frequency in hertz.
|
||||
func CPUFrequency() uint32 {
|
||||
return 8000000
|
||||
}
|
||||
|
||||
const (
|
||||
P5 Pin = PB0
|
||||
P6 Pin = PB1
|
||||
P7 Pin = PB2
|
||||
P2 Pin = PB3
|
||||
P3 Pin = PB4
|
||||
P1 Pin = PB5
|
||||
|
||||
LED = P1
|
||||
BUTTON_LEFT = P7
|
||||
BUTTON_RIGHT = P5
|
||||
SPEAKER = P6
|
||||
)
|
||||
@@ -0,0 +1,183 @@
|
||||
//go:build metro_rp2350
|
||||
|
||||
package machine
|
||||
|
||||
// GPIO pins
|
||||
const (
|
||||
GP0 Pin = GPIO0
|
||||
GP1 Pin = GPIO1
|
||||
GP2 Pin = GPIO2
|
||||
GP3 Pin = GPIO3
|
||||
GP4 Pin = GPIO4
|
||||
GP5 Pin = GPIO5
|
||||
GP6 Pin = GPIO6
|
||||
GP7 Pin = GPIO7
|
||||
GP8 Pin = GPIO8
|
||||
GP9 Pin = GPIO9
|
||||
GP10 Pin = GPIO10
|
||||
GP11 Pin = GPIO11
|
||||
GP12 Pin = GPIO12
|
||||
GP13 Pin = GPIO13
|
||||
GP14 Pin = GPIO14
|
||||
GP15 Pin = GPIO15
|
||||
GP16 Pin = GPIO16
|
||||
GP17 Pin = GPIO17
|
||||
GP18 Pin = GPIO18
|
||||
GP19 Pin = GPIO19
|
||||
GP20 Pin = GPIO20
|
||||
GP21 Pin = GPIO21
|
||||
GP22 Pin = GPIO22
|
||||
GP23 Pin = GPIO23
|
||||
GP24 Pin = GPIO24
|
||||
GP25 Pin = GPIO25
|
||||
GP26 Pin = GPIO26
|
||||
GP27 Pin = GPIO27
|
||||
GP28 Pin = GPIO28
|
||||
GP29 Pin = GPIO29
|
||||
GP30 Pin = GPIO30
|
||||
GP31 Pin = GPIO31
|
||||
GP32 Pin = GPIO32
|
||||
GP33 Pin = GPIO33
|
||||
GP34 Pin = GPIO34
|
||||
GP35 Pin = GPIO35
|
||||
GP36 Pin = GPIO36
|
||||
GP37 Pin = GPIO37
|
||||
GP38 Pin = GPIO38
|
||||
GP39 Pin = GPIO39
|
||||
GP40 Pin = GPIO40
|
||||
GP41 Pin = GPIO41
|
||||
GP42 Pin = GPIO42
|
||||
GP43 Pin = GPIO43
|
||||
GP44 Pin = GPIO44
|
||||
GP45 Pin = GPIO45
|
||||
GP46 Pin = GPIO46
|
||||
|
||||
// Boot button
|
||||
BUTTON Pin = GPIO24
|
||||
|
||||
// Onboard LED
|
||||
LED Pin = GPIO23
|
||||
|
||||
// Onboard NeoPixel
|
||||
NEOPIXEL Pin = GPIO25
|
||||
WS2812 Pin = GPIO25
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// Arduino-header digital pins
|
||||
const (
|
||||
RX Pin = GPIO1
|
||||
TX Pin = GPIO0
|
||||
D2 Pin = GPIO2
|
||||
D3 Pin = GPIO3
|
||||
D4 Pin = GPIO4
|
||||
D5 Pin = GPIO5
|
||||
D6 Pin = GPIO6
|
||||
D7 Pin = GPIO7
|
||||
D8 Pin = GPIO8
|
||||
D9 Pin = GPIO9
|
||||
D10 Pin = GPIO10
|
||||
D11 Pin = GPIO11
|
||||
D22 Pin = GPIO22
|
||||
D23 Pin = GPIO23
|
||||
)
|
||||
|
||||
// Arduino-header analog pins
|
||||
const (
|
||||
A0 Pin = GPIO41
|
||||
A1 Pin = GPIO42
|
||||
A2 Pin = GPIO43
|
||||
A3 Pin = GPIO44
|
||||
A4 Pin = GPIO45
|
||||
A5 Pin = GPIO46
|
||||
)
|
||||
|
||||
// I2C Default pins on Raspberry Pico.
|
||||
const (
|
||||
I2C0_SDA_PIN = GP20
|
||||
I2C0_SCL_PIN = GP21
|
||||
|
||||
I2C1_SDA_PIN = GP2
|
||||
I2C1_SCL_PIN = GP3
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO18
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO19 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO16 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO30
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO31 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO28 // Rx
|
||||
|
||||
// SPI header pins
|
||||
MOSI Pin = SPI1_SDO_PIN
|
||||
MISO Pin = SPI1_SDI_PIN
|
||||
SCK Pin = SPI1_SCK_PIN
|
||||
)
|
||||
|
||||
// SD card reader pins
|
||||
const (
|
||||
SD_SCK = GPIO34
|
||||
SD_MOSI = GPIO35
|
||||
SD_MISO = GPIO36
|
||||
SDIO_DATA1 = GPIO37
|
||||
SDIO_DATA2 = GPIO38
|
||||
SD_CS = GPIO39
|
||||
SD_CARD_DETECT = GPIO40
|
||||
)
|
||||
|
||||
// HSTX pins
|
||||
const (
|
||||
CKN Pin = GPIO15
|
||||
CKP Pin = GPIO14
|
||||
D0N Pin = GPIO19
|
||||
D0P Pin = GPIO18
|
||||
D1N Pin = GPIO17
|
||||
D1P Pin = GPIO16
|
||||
D2N Pin = GPIO13
|
||||
D2P Pin = GPIO12
|
||||
D26 Pin = GPIO26
|
||||
D27 Pin = GPIO27
|
||||
SCL Pin = GPIO21
|
||||
SDA Pin = GPIO20
|
||||
)
|
||||
|
||||
// USB host header pins
|
||||
const (
|
||||
USB_HOST_DATA_PLUS Pin = GPIO32
|
||||
USB_HOST_DATA_MINUS Pin = GPIO33
|
||||
USB_HOST_5V_POWER Pin = GPIO29
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Metro RP2350"
|
||||
usb_STRING_MANUFACTURER = "Adafruit"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x239A
|
||||
usb_PID uint16 = 0x814E
|
||||
)
|
||||
@@ -0,0 +1,173 @@
|
||||
//go:build pico2_ice
|
||||
|
||||
// Most of the info is from
|
||||
// https://pico2-ice.tinyvision.ai/md_pinout.html although
|
||||
// (2025-09-07) RP4 appears twice in that pinout - the schematic is
|
||||
// more clear. Consistent with other RPi boards, we use GPn instead of
|
||||
// RPn to reference the RPi connected pins.
|
||||
|
||||
package machine
|
||||
|
||||
// GPIO pins
|
||||
const (
|
||||
GP0 = GPIO0
|
||||
GP1 = GPIO1
|
||||
GP2 = GPIO2
|
||||
GP3 = GPIO3
|
||||
GP4 = GPIO4
|
||||
GP5 = GPIO5
|
||||
GP6 = GPIO6
|
||||
GP7 = GPIO7
|
||||
GP8 = GPIO8
|
||||
GP9 = GPIO9
|
||||
GP10 = GPIO10
|
||||
GP11 = GPIO11
|
||||
GP12 = GPIO12
|
||||
GP13 = GPIO13
|
||||
GP14 = GPIO14
|
||||
GP15 = GPIO15
|
||||
GP16 = GPIO16
|
||||
GP17 = GPIO17
|
||||
GP18 = GPIO18
|
||||
GP19 = GPIO19
|
||||
GP20 = GPIO20
|
||||
GP21 = GPIO21
|
||||
GP22 = GPIO22
|
||||
GP23 = GPIO23
|
||||
GP24 = GPIO24
|
||||
GP25 = GPIO25
|
||||
GP26 = GPIO26
|
||||
GP27 = GPIO27
|
||||
GP28 = GPIO28
|
||||
GP29 = GPIO29
|
||||
GP30 = GPIO30
|
||||
GP31 = GPIO31
|
||||
GP32 = GPIO32
|
||||
GP33 = GPIO33
|
||||
GP34 = GPIO34
|
||||
GP35 = GPIO35
|
||||
GP36 = GPIO36
|
||||
GP37 = GPIO37
|
||||
GP38 = GPIO38
|
||||
GP39 = GPIO39
|
||||
GP40 = GPIO40
|
||||
GP41 = GPIO41
|
||||
GP42 = GPIO42
|
||||
GP43 = GPIO43
|
||||
GP44 = GPIO44
|
||||
GP45 = GPIO45
|
||||
GP46 = GPIO46
|
||||
GP47 = GPIO47
|
||||
|
||||
// RPi pins shared with ICE. The ICE number is what appears on
|
||||
// the board silkscreen.
|
||||
ICE9 = GP28
|
||||
ICE11 = GP29
|
||||
ICE14 = GP7
|
||||
ICE15 = GP6
|
||||
ICE16 = GP5
|
||||
ICE17 = GP4
|
||||
ICE18 = GP27
|
||||
ICE19 = GP23
|
||||
ICE20 = GP22
|
||||
ICE21 = GP26
|
||||
ICE23 = GP25
|
||||
ICE25 = GP30
|
||||
ICE26 = GP24
|
||||
ICE27 = GP20
|
||||
|
||||
// FPGA Clock pin.
|
||||
ICE35_G0 = GP21
|
||||
|
||||
// Silkscreen & Pinout names
|
||||
ICE_SSN = ICE16
|
||||
ICE_SO = ICE14
|
||||
ICE_SI = ICE17
|
||||
ICE_CK = ICE15
|
||||
SD = GP2
|
||||
SC = GP3
|
||||
|
||||
FPGA_RSTN = GP31
|
||||
A3 = GP32
|
||||
A1 = GP33
|
||||
A4 = GP34
|
||||
A2 = GP35
|
||||
B3 = GP36
|
||||
B1 = GP37
|
||||
B4 = GP38
|
||||
B2 = GP39
|
||||
N0 = GP40 // On the board these are labeled "~0"
|
||||
N1 = GP41
|
||||
N2 = GP42
|
||||
N3 = GP43
|
||||
N4 = GP44
|
||||
N5 = GP45
|
||||
N6 = GP46
|
||||
|
||||
// Functions from Schematic.
|
||||
ICE_DONE = GP40
|
||||
USB_BOOT = GP42
|
||||
|
||||
// Button
|
||||
SW1 = GP42
|
||||
BOOTSEL = GP42
|
||||
|
||||
// Tricolor LEDs
|
||||
LED_RED = GP1
|
||||
LED_GREEN = GP0
|
||||
LED_BLUE = GP9
|
||||
|
||||
// Onboard LED
|
||||
LED = LED_GREEN
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// This board does not define default i2c pins.
|
||||
const (
|
||||
I2C0_SDA_PIN = NoPin
|
||||
I2C0_SCL_PIN = NoPin
|
||||
I2C1_SDA_PIN = NoPin
|
||||
I2C1_SCL_PIN = NoPin
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO18
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO19 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO16 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO10
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO11 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Pico2"
|
||||
usb_STRING_MANUFACTURER = "Raspberry Pi"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2E8A
|
||||
usb_PID uint16 = 0x000A
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
//go:build xiao_esp32s3
|
||||
|
||||
// This file contains the pin mappings for the Seeed XIAO ESP32S3 boards.
|
||||
//
|
||||
// Seeed Studio XIAO ESP32S3 is an IoT mini development board based on
|
||||
// the Espressif ESP32-S3 WiFi/Bluetooth dual-mode chip.
|
||||
//
|
||||
// - https://www.seeedstudio.com/XIAO-ESP32S3-p-5627.html
|
||||
// - https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
|
||||
|
||||
package machine
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
D0 = GPIO1
|
||||
D1 = GPIO2
|
||||
D2 = GPIO3
|
||||
D3 = GPIO4
|
||||
D4 = GPIO5
|
||||
D5 = GPIO6
|
||||
D6 = GPIO43
|
||||
D7 = GPIO44
|
||||
D8 = GPIO7
|
||||
D9 = GPIO8
|
||||
D10 = GPIO9
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 = GPIO1
|
||||
A1 = GPIO2
|
||||
A2 = GPIO3
|
||||
A3 = GPIO4
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART_RX_PIN = GPIO44
|
||||
UART_TX_PIN = GPIO43
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = GPIO5
|
||||
SCL_PIN = GPIO6
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI_SCK_PIN = GPIO7
|
||||
SPI_SDI_PIN = GPIO9
|
||||
SPI_SDO_PIN = GPIO8
|
||||
)
|
||||
|
||||
// Onboard LEDs
|
||||
const (
|
||||
LED = GPIO21
|
||||
)
|
||||
@@ -43,6 +43,11 @@ type BlockDevice interface {
|
||||
io.ReaderAt
|
||||
|
||||
// WriteAt writes the given number of bytes to the block device.
|
||||
//
|
||||
// This interface directly writes data to the underlying block device.
|
||||
// Different kinds of devices have different requirements: most can only
|
||||
// write data after the page has been erased, and many can only write data
|
||||
// with specific alignment (such as 4-byte alignment).
|
||||
io.WriterAt
|
||||
|
||||
// Size returns the number of bytes in this block device.
|
||||
|
||||
+31
-1
@@ -1,6 +1,9 @@
|
||||
package machine
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTimeoutRNG = errors.New("machine: RNG Timeout")
|
||||
@@ -62,3 +65,30 @@ func (p Pin) Low() {
|
||||
type ADC struct {
|
||||
Pin Pin
|
||||
}
|
||||
|
||||
// Convert the pointer to a uintptr, to be used for memory I/O (DMA for
|
||||
// example). It also means the pointer is "gone" as far as the compiler is
|
||||
// concerned, and a GC cycle might deallocate the object. To prevent this from
|
||||
// happening, also call keepAliveNoEscape at a point after the address isn't
|
||||
// accessed anymore by the hardware.
|
||||
// The only exception is if the pointer is accessed later in a volatile way
|
||||
// (volatile read/write), which also forces the value to stay alive until that
|
||||
// point.
|
||||
//
|
||||
// This function is treated specially by the compiler to mark the 'ptr'
|
||||
// parameter as not escaping.
|
||||
//
|
||||
// TODO: this function should eventually be replaced with the proposed ptrtoaddr
|
||||
// instruction in LLVM. See:
|
||||
// https://discourse.llvm.org/t/clarifiying-the-semantics-of-ptrtoint/83987/10
|
||||
// https://github.com/llvm/llvm-project/pull/139357
|
||||
func unsafeNoEscape(ptr unsafe.Pointer) uintptr {
|
||||
return uintptr(ptr)
|
||||
}
|
||||
|
||||
// Make sure the given pointer stays alive until this point. This is similar to
|
||||
// runtime.KeepAlive, with the difference that it won't let the pointer escape.
|
||||
// This is typically used together with unsafeNoEscape.
|
||||
//
|
||||
// This is a compiler intrinsic.
|
||||
func keepAliveNoEscape(ptr unsafe.Pointer)
|
||||
|
||||
@@ -337,7 +337,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
|
||||
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
sendUSBPacket(ep, data)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
@@ -351,27 +351,28 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
|
||||
//
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
func sendUSBPacket(ep uint32, data []byte) {
|
||||
// Select the corresponding buffer.
|
||||
buffer := udd_ep_control_cache_buffer[:]
|
||||
if ep != 0 {
|
||||
buffer = udd_ep_in_cache_buffer[ep][:]
|
||||
}
|
||||
|
||||
// Set endpoint address for sending data
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
}
|
||||
// Copy the packet to the buffer.
|
||||
copy(buffer[:len(data)], data)
|
||||
|
||||
// Select the corresponding endpoint descriptor.
|
||||
endpoint := &usbEndpointDescriptors[ep].DeviceDescBank[1]
|
||||
|
||||
// Set the endpoint address.
|
||||
endpoint.ADDR.Set(uint32(uintptr(unsafe.Pointer(unsafe.SliceData(buffer)))))
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
endpoint.PCKSIZE.SetBits((uint32(len(data)) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
|
||||
@@ -340,7 +340,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
|
||||
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
sendUSBPacket(ep, data)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
@@ -354,27 +354,28 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
|
||||
//
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
func sendUSBPacket(ep uint32, data []byte) {
|
||||
// Select the corresponding buffer.
|
||||
buffer := udd_ep_control_cache_buffer[:]
|
||||
if ep != 0 {
|
||||
buffer = udd_ep_in_cache_buffer[ep][:]
|
||||
}
|
||||
|
||||
// Set endpoint address for sending data
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
}
|
||||
// Copy the packet to the buffer.
|
||||
copy(buffer[:len(data)], data)
|
||||
|
||||
// Select the corresponding endpoint descriptor.
|
||||
endpoint := &usbEndpointDescriptors[ep].DeviceDescBank[1]
|
||||
|
||||
// Set the endpoint address.
|
||||
endpoint.ADDR.Set(uint32(uintptr(unsafe.Pointer(unsafe.SliceData(buffer)))))
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
endpoint.PCKSIZE.SetBits((uint32(len(data)) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
|
||||
@@ -519,6 +519,10 @@ type Serialer interface {
|
||||
RTS() bool
|
||||
}
|
||||
|
||||
func initUSB() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// USB Serial/JTAG Controller
|
||||
// See esp32-c3_technical_reference_manual_en.pdf
|
||||
// pg. 736
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
//go:build esp32s3
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/esp"
|
||||
"errors"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const deviceName = esp.Device
|
||||
|
||||
const xtalClock = 40_000000 // 40MHz
|
||||
const apbClock = 80_000000 // 80MHz
|
||||
const cryptoPWMClock = 160_000000 // 160MHz
|
||||
|
||||
// GetCPUFrequency returns the current CPU frequency of the chip.
|
||||
func GetCPUFrequency() (uint32, error) {
|
||||
switch esp.SYSTEM.GetSYSCLK_CONF_SOC_CLK_SEL() {
|
||||
case 0:
|
||||
return xtalClock / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil
|
||||
case 1:
|
||||
switch esp.SYSTEM.GetCPU_PER_CONF_CPUPERIOD_SEL() {
|
||||
case 0:
|
||||
return 80e6, nil
|
||||
case 1:
|
||||
return 160e6, nil
|
||||
case 2:
|
||||
// If esp.SYSTEM.GetCPU_PER_CONF_PLL_FREQ_SEL() == 1, this is undefined
|
||||
return 240e6, nil
|
||||
}
|
||||
case 2:
|
||||
//RC Fast Clock
|
||||
return (175e5) / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil
|
||||
}
|
||||
return 0, errors.New("machine: Unable to determine current cpu frequency")
|
||||
}
|
||||
|
||||
// SetCPUFrequency sets the frequency of the CPU to one of several targets
|
||||
func SetCPUFrequency(frequency uint32) error {
|
||||
// Always assume we are on PLL. Lower frequencies can be set with a different
|
||||
// clock source, but this will change the behavior of APB clock and Crypto PWM
|
||||
// clock
|
||||
//esp.SYSTEM.SetSYSCLK_CONF_SOC_CLK_SEL(1)
|
||||
|
||||
switch frequency {
|
||||
case 80_000000:
|
||||
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(0)
|
||||
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0) // Reduce PLL freq when possible
|
||||
return nil
|
||||
case 160_000000:
|
||||
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(1)
|
||||
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0)
|
||||
return nil
|
||||
case 240_000000:
|
||||
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(1) // Increase PLL freq when needed
|
||||
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(2)
|
||||
return nil
|
||||
}
|
||||
return errors.New("machine: Unsupported CPU frequency selected. Supported: 80, 160, 240 MHz")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
|
||||
)
|
||||
|
||||
const (
|
||||
PinOutput PinMode = iota
|
||||
PinInput
|
||||
PinInputPullup
|
||||
PinInputPulldown
|
||||
)
|
||||
|
||||
// Hardware pin numbers
|
||||
const (
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
GPIO7 Pin = 7
|
||||
GPIO8 Pin = 8
|
||||
GPIO9 Pin = 9
|
||||
GPIO10 Pin = 10
|
||||
GPIO11 Pin = 11
|
||||
GPIO12 Pin = 12
|
||||
GPIO13 Pin = 13
|
||||
GPIO14 Pin = 14
|
||||
GPIO15 Pin = 15
|
||||
GPIO16 Pin = 16
|
||||
GPIO17 Pin = 17
|
||||
GPIO18 Pin = 18
|
||||
GPIO19 Pin = 19
|
||||
GPIO20 Pin = 20
|
||||
GPIO21 Pin = 21
|
||||
GPIO26 Pin = 26
|
||||
GPIO27 Pin = 27
|
||||
GPIO28 Pin = 28
|
||||
GPIO29 Pin = 29
|
||||
GPIO30 Pin = 30
|
||||
GPIO31 Pin = 31
|
||||
GPIO32 Pin = 32
|
||||
GPIO33 Pin = 33
|
||||
GPIO34 Pin = 34
|
||||
GPIO35 Pin = 35
|
||||
GPIO36 Pin = 36
|
||||
GPIO37 Pin = 37
|
||||
GPIO38 Pin = 38
|
||||
GPIO39 Pin = 39
|
||||
GPIO40 Pin = 40
|
||||
GPIO41 Pin = 41
|
||||
GPIO42 Pin = 42
|
||||
GPIO43 Pin = 43
|
||||
GPIO44 Pin = 44
|
||||
GPIO45 Pin = 45
|
||||
GPIO46 Pin = 46
|
||||
GPIO47 Pin = 47
|
||||
GPIO48 Pin = 48
|
||||
)
|
||||
|
||||
// Configure this pin with the given configuration.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
// Output function 256 is a special value reserved for use as a regular GPIO
|
||||
// pin. Peripherals (SPI etc) can set a custom output function by calling
|
||||
// lowercase configure() instead with a signal name.
|
||||
p.configure(config, 256)
|
||||
}
|
||||
|
||||
// configure is the same as Configure, but allows for setting a specific input
|
||||
// or output signal.
|
||||
// Signals are always routed through the GPIO matrix for simplicity. Output
|
||||
// signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal
|
||||
// to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG,
|
||||
// which sets the pin to use for a particular input signal.
|
||||
func (p Pin) configure(config PinConfig, signal uint32) {
|
||||
if p == NoPin {
|
||||
// This simplifies pin configuration in peripherals such as SPI.
|
||||
return
|
||||
}
|
||||
|
||||
ioConfig := uint32(0)
|
||||
|
||||
// MCU_SEL: Function 1 is always GPIO
|
||||
ioConfig |= (1 << esp.IO_MUX_GPIO_MCU_SEL_Pos)
|
||||
|
||||
// FUN_IE: Make this pin an input pin (always set for GPIO operation)
|
||||
ioConfig |= esp.IO_MUX_GPIO_FUN_IE
|
||||
|
||||
// DRV: Set drive strength to 20 mA as a default. Pins 17 and 18 are special
|
||||
var drive uint32
|
||||
if p == GPIO17 || p == GPIO18 {
|
||||
drive = 1 // 20 mA
|
||||
} else {
|
||||
drive = 2 // 20 mA
|
||||
}
|
||||
ioConfig |= (drive << esp.IO_MUX_GPIO_FUN_DRV_Pos)
|
||||
|
||||
// WPU/WPD: Select pull mode.
|
||||
if config.Mode == PinInputPullup {
|
||||
ioConfig |= esp.IO_MUX_GPIO_FUN_WPU
|
||||
} else if config.Mode == PinInputPulldown {
|
||||
ioConfig |= esp.IO_MUX_GPIO_FUN_WPD
|
||||
}
|
||||
|
||||
// Set configuration
|
||||
ioRegister := p.ioMuxReg()
|
||||
ioRegister.Set(ioConfig)
|
||||
|
||||
switch config.Mode {
|
||||
case PinOutput:
|
||||
// Set the 'output enable' bit.
|
||||
if p < 32 {
|
||||
esp.GPIO.ENABLE_W1TS.Set(1 << p)
|
||||
} else {
|
||||
esp.GPIO.ENABLE1_W1TS.Set(1 << (p - 32))
|
||||
}
|
||||
// Set the signal to read the output value from. It can be a peripheral
|
||||
// output signal, or the special value 256 which indicates regular GPIO
|
||||
// usage.
|
||||
p.outFunc().Set(signal)
|
||||
case PinInput, PinInputPullup, PinInputPulldown:
|
||||
// Clear the 'output enable' bit.
|
||||
if p < 32 {
|
||||
esp.GPIO.ENABLE_W1TC.Set(1 << p)
|
||||
} else {
|
||||
esp.GPIO.ENABLE1_W1TC.Set(1 << (p - 32))
|
||||
}
|
||||
if signal != 256 {
|
||||
// Signal is a peripheral function (not a simple GPIO). Connect this
|
||||
// signal to the pin.
|
||||
// Note that outFunc and inFunc work in the opposite direction.
|
||||
// outFunc configures a pin to use a given output signal, while
|
||||
// inFunc specifies a pin to use to read the signal from.
|
||||
inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ioMuxReg returns the IO_MUX_n_REG register used for configuring the io mux for
|
||||
// this pin
|
||||
func (p Pin) ioMuxReg() *volatile.Register32 {
|
||||
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.IO_MUX.GPIO0), uintptr(p)*4))
|
||||
}
|
||||
|
||||
// outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the
|
||||
// output function selection.
|
||||
func (p Pin) outFunc() *volatile.Register32 {
|
||||
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
|
||||
}
|
||||
|
||||
// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
|
||||
// function selection.
|
||||
func inFunc(signal uint32) *volatile.Register32 {
|
||||
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4))
|
||||
}
|
||||
|
||||
// Set the pin to high or low.
|
||||
// Warning: only use this on an output pin!
|
||||
func (p Pin) Set(value bool) {
|
||||
if value {
|
||||
reg, mask := p.portMaskSet()
|
||||
reg.Set(mask)
|
||||
} else {
|
||||
reg, mask := p.portMaskClear()
|
||||
reg.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||
// implement bit-banged drivers.
|
||||
//
|
||||
// Warning: only use this on an output pin!
|
||||
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
reg, mask := p.portMaskSet()
|
||||
return ®.Reg, mask
|
||||
}
|
||||
|
||||
// Return the register and mask to disable a given GPIO pin. This can be used to
|
||||
// implement bit-banged drivers.
|
||||
//
|
||||
// Warning: only use this on an output pin!
|
||||
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
reg, mask := p.portMaskClear()
|
||||
return ®.Reg, mask
|
||||
}
|
||||
|
||||
func (p Pin) portMaskSet() (*volatile.Register32, uint32) {
|
||||
if p < 32 {
|
||||
return &esp.GPIO.OUT_W1TS, 1 << p
|
||||
} else {
|
||||
return &esp.GPIO.OUT1_W1TS, 1 << (p - 32)
|
||||
}
|
||||
}
|
||||
|
||||
func (p Pin) portMaskClear() (*volatile.Register32, uint32) {
|
||||
if p < 32 {
|
||||
return &esp.GPIO.OUT_W1TC, 1 << p
|
||||
} else {
|
||||
return &esp.GPIO.OUT1_W1TC, 1 << (p - 32)
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the current value of a GPIO pin when the pin is configured as an
|
||||
// input or as an output.
|
||||
func (p Pin) Get() bool {
|
||||
if p < 32 {
|
||||
return esp.GPIO.IN.Get()&(1<<p) != 0
|
||||
} else {
|
||||
return esp.GPIO.IN1.Get()&(1<<(p-32)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
|
||||
UART2 = &_UART2
|
||||
_UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()}
|
||||
)
|
||||
|
||||
type UART struct {
|
||||
Bus *esp.UART_Type
|
||||
Buffer *RingBuffer
|
||||
}
|
||||
|
||||
func (uart *UART) Configure(config UARTConfig) {
|
||||
if config.BaudRate == 0 {
|
||||
config.BaudRate = 115200
|
||||
}
|
||||
// Crystal clock source is selected by default
|
||||
uart.Bus.CLKDIV.Set(xtalClock / config.BaudRate)
|
||||
}
|
||||
|
||||
func (uart *UART) writeByte(b byte) error {
|
||||
for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
|
||||
// Read UART_TXFIFO_CNT from the status register, which indicates how
|
||||
// many bytes there are in the transmit buffer. Wait until there are
|
||||
// less than 128 bytes in this buffer (the default buffer size).
|
||||
}
|
||||
uart.Bus.FIFO.Set(uint32(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) flush() {}
|
||||
|
||||
// TODO: SPI
|
||||
@@ -3,7 +3,9 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/nrf"
|
||||
"errors"
|
||||
"internal/binary"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
@@ -380,6 +382,10 @@ func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
// If the length of p is not long enough it will be padded with 0xFF bytes.
|
||||
// This method assumes that the destination is already erased.
|
||||
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil // nothing to do (and it would fail in sd_flash_write)
|
||||
}
|
||||
|
||||
if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
|
||||
return 0, errFlashCannotWritePastEOF
|
||||
}
|
||||
@@ -387,6 +393,35 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
address := FlashDataStart() + uintptr(off)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
// When the SoftDevice is enabled, access to the flash is restricted and
|
||||
// must go through the SoftDevice API.
|
||||
if isSoftDeviceEnabled() {
|
||||
// Call sd_flash_write, which is SVC_SOC_BASE + 9 in all the
|
||||
// SoftDevices I've checked.
|
||||
// Documentation:
|
||||
// https://docs.nordicsemi.com/bundle/s140_v6.0.0_api/page/group_n_r_f_s_o_c_f_u_n_c_t_i_o_n_s.html
|
||||
numberOfWords := len(padded) / 4 // flash access goes in 32-bit words
|
||||
result := arm.SVCall3(0x20+9, address, &padded[0], uint32(numberOfWords))
|
||||
if result != 0 {
|
||||
// Could not queue flash operation? Not sure when this can
|
||||
// happen.
|
||||
return 0, flashError
|
||||
}
|
||||
|
||||
// Wait until the SoftDevice is finished.
|
||||
flashStatus = flashStatusBusy
|
||||
for flashStatus == flashStatusBusy {
|
||||
handleSoftDeviceEvents()
|
||||
}
|
||||
|
||||
// Check whether the operation was successful.
|
||||
if flashStatus != flashStatusOk {
|
||||
flashStatus = flashStatusOk
|
||||
return 0, flashError
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
waitWhileFlashBusy()
|
||||
|
||||
nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Wen)
|
||||
@@ -428,6 +463,40 @@ func (f flashBlockDevice) EraseBlockSize() int64 {
|
||||
// supports this. The start and len parameters are in block numbers, use
|
||||
// EraseBlockSize to map addresses to blocks.
|
||||
func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
// When the SoftDevice is enabled, access to the flash is restricted and
|
||||
// must go through the SoftDevice API.
|
||||
if isSoftDeviceEnabled() {
|
||||
for i := range uint32(len) {
|
||||
flashPage := uint32(FlashDataStart())/eraseBlockSizeValue + uint32(start) + i
|
||||
|
||||
// Call sd_flash_page_erase, which is SVC_SOC_BASE + 8 in all the
|
||||
// SoftDevices I've checked.
|
||||
// Documentation:
|
||||
// https://docs.nordicsemi.com/bundle/s140_v6.0.0_api/page/group_n_r_f_s_o_c_f_u_n_c_t_i_o_n_s.html#ga9c93dd94a138ad8b5ed3693ea38ffb3e
|
||||
result := arm.SVCall1(0x20+8, flashPage)
|
||||
if result != 0 {
|
||||
// Could not queue flash operation? Not sure when this can
|
||||
// happen.
|
||||
return flashError
|
||||
}
|
||||
|
||||
// Wait until the SoftDevice is finished.
|
||||
flashStatus = flashStatusBusy
|
||||
for flashStatus == flashStatusBusy {
|
||||
handleSoftDeviceEvents()
|
||||
}
|
||||
|
||||
// Check whether the operation was successful.
|
||||
if flashStatus != flashStatusOk {
|
||||
flashStatus = flashStatusOk
|
||||
return flashError
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDevice is not used or enabled. Use NVIC directly.
|
||||
|
||||
address := FlashDataStart() + uintptr(start*f.EraseBlockSize())
|
||||
waitWhileFlashBusy()
|
||||
|
||||
@@ -447,3 +516,52 @@ func waitWhileFlashBusy() {
|
||||
for nrf.NVMC.GetREADY() != nrf.NVMC_READY_READY_Ready {
|
||||
}
|
||||
}
|
||||
|
||||
var flashError = errors.New("machine: flash operation failed")
|
||||
|
||||
const (
|
||||
flashStatusOk = iota
|
||||
flashStatusError
|
||||
flashStatusBusy
|
||||
)
|
||||
|
||||
var flashStatus uint8 = flashStatusOk
|
||||
|
||||
var sdEvent uint32
|
||||
|
||||
// Process all queued SoftDevice events. May only be called when the SoftDevice is enabled.
|
||||
//
|
||||
// Normally these are handled in the same interrupt where Bluetooth events are
|
||||
// handled. But in TinyGo, that's complicated. One option would be to put it in
|
||||
// the tinygo.org/x/bluetooth package, but that would cause a circular
|
||||
// dependency between the machine and the bluetooth package. Another would be to
|
||||
// put it here, but let the bluetooth package call handleSoftDeviceEvents, but
|
||||
// that relies on updating the bluetooth package at the same time. As a
|
||||
// compromise, these events are handled directly where they are expected (here
|
||||
// in the machine package). This works in practice since there are only very few
|
||||
// of such events (at the moment, only flash-related ones which is in the
|
||||
// machine package anyway).
|
||||
func handleSoftDeviceEvents() {
|
||||
for {
|
||||
var result uintptr
|
||||
if nrf.Device == "nrf52" || nrf.Device == "nrf52840" || nrf.Device == "nrf52833" {
|
||||
// sd_evt_get: SOC_SVC_BASE_NOT_AVAILABLE + 31
|
||||
result = arm.SVCall1(0x2C+31, &sdEvent)
|
||||
} else {
|
||||
return // TODO: nrf51 etc
|
||||
}
|
||||
if result != 0 {
|
||||
// Some error occured. The only possible error is
|
||||
// NRF_ERROR_NOT_FOUND, which means there are no more events.
|
||||
return
|
||||
}
|
||||
|
||||
// The following events are the same numbers in all SoftDevices I've checked.
|
||||
switch sdEvent {
|
||||
case 2: // NRF_EVT_FLASH_OPERATION_SUCCESS
|
||||
flashStatus = flashStatusOk
|
||||
case 3: // NRF_EVT_FLASH_OPERATION_ERROR
|
||||
flashStatus = flashStatusError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,3 +69,5 @@ const eraseBlockSizeValue = 4096
|
||||
func eraseBlockSize() int64 {
|
||||
return eraseBlockSizeValue
|
||||
}
|
||||
|
||||
const spiMaxBufferSize = 255 // from the datasheet: TXD.MAXCNT and RXD.MAXCNT
|
||||
|
||||
@@ -90,3 +90,5 @@ const eraseBlockSizeValue = 4096
|
||||
func eraseBlockSize() int64 {
|
||||
return eraseBlockSizeValue
|
||||
}
|
||||
|
||||
const spiMaxBufferSize = 0xffff // from the datasheet: TXD.MAXCNT and RXD.MAXCNT
|
||||
|
||||
@@ -108,3 +108,9 @@ const eraseBlockSizeValue = 4096
|
||||
func eraseBlockSize() int64 {
|
||||
return eraseBlockSizeValue
|
||||
}
|
||||
|
||||
const spiMaxBufferSize = 0xffff // from the datasheet: TXD.MAXCNT and RXD.MAXCNT
|
||||
|
||||
// ADC instance for the VDDH input pin. This pin is typically connected to USB
|
||||
// input voltage (~5V) or directly to a battery.
|
||||
var ADC_VDDH = ADC{adcVDDHPin}
|
||||
|
||||
@@ -256,7 +256,7 @@ func initEndpoint(ep, config uint32) {
|
||||
|
||||
// SendUSBInPacket sends a packet for USBHID (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
sendUSBPacket(ep, data)
|
||||
|
||||
// clear transfer complete flag
|
||||
nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4)
|
||||
@@ -267,33 +267,32 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
|
||||
//
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
func sendUSBPacket(ep uint32, data []byte) {
|
||||
// Select the corresponding buffer.
|
||||
count := len(data)
|
||||
if 0 < int(maxsize) && int(maxsize) < count {
|
||||
count = int(maxsize)
|
||||
}
|
||||
|
||||
var buffer []byte
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:count])
|
||||
buffer = udd_ep_control_cache_buffer[:]
|
||||
if count > usb.EndpointPacketSize {
|
||||
// The packet must be sent in chunks.
|
||||
sendOnEP0DATADONE.offset = usb.EndpointPacketSize
|
||||
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset]
|
||||
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[usb.EndpointPacketSize]
|
||||
sendOnEP0DATADONE.count = count - usb.EndpointPacketSize
|
||||
count = usb.EndpointPacketSize
|
||||
}
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&udd_ep_control_cache_buffer[0],
|
||||
count,
|
||||
)
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:count])
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&udd_ep_in_cache_buffer[ep][0],
|
||||
count,
|
||||
)
|
||||
buffer = udd_ep_in_cache_buffer[ep][:]
|
||||
}
|
||||
|
||||
// Copy the packet to the buffer.
|
||||
copy(buffer[:len(data)], data)
|
||||
|
||||
// Send the first chunk of the packet.
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&buffer[0],
|
||||
count,
|
||||
)
|
||||
}
|
||||
|
||||
func handleEndpointRx(ep uint32) []byte {
|
||||
|
||||
@@ -49,7 +49,7 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
||||
|
||||
// Configure for a single shot to perform both write and read (as applicable)
|
||||
if len(w) != 0 {
|
||||
i2c.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
|
||||
i2c.Bus.TXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(w)))))
|
||||
i2c.Bus.TXD.MAXCNT.Set(uint32(len(w)))
|
||||
|
||||
// If no read, immediately signal stop after TX
|
||||
@@ -58,7 +58,7 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
||||
}
|
||||
}
|
||||
if len(r) != 0 {
|
||||
i2c.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
|
||||
i2c.Bus.RXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(r)))))
|
||||
i2c.Bus.RXD.MAXCNT.Set(uint32(len(r)))
|
||||
|
||||
// Auto-start Rx after Tx and Stop after Rx
|
||||
@@ -78,17 +78,22 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
||||
// Allow scheduler to run
|
||||
gosched()
|
||||
|
||||
// Handle errors by ensuring STOP sent on bus
|
||||
if i2c.Bus.EVENTS_ERROR.Get() != 0 {
|
||||
// Handle first occurrence of error by ensuring STOP sent on bus
|
||||
if err == nil && i2c.Bus.EVENTS_ERROR.Get() != 0 {
|
||||
err = twiCError(i2c.Bus.ERRORSRC.Get())
|
||||
if i2c.Bus.EVENTS_STOPPED.Get() == 0 {
|
||||
// STOP cannot be sent during SUSPEND
|
||||
i2c.Bus.TASKS_RESUME.Set(1)
|
||||
i2c.Bus.TASKS_STOP.Set(1)
|
||||
}
|
||||
err = twiCError(i2c.Bus.ERRORSRC.Get())
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the w and r buffers stay alive until this point, so they won't
|
||||
// be garbage collected while the buffers are used by the hardware.
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(w)))
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(r)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,7 +122,7 @@ func (i2c *I2C) Listen(addr uint8) error {
|
||||
//
|
||||
// For request events, the caller MUST call `Reply` to avoid hanging the i2c bus indefinitely.
|
||||
func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) {
|
||||
i2c.BusT.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
|
||||
i2c.BusT.RXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(buf)))))
|
||||
i2c.BusT.RXD.MAXCNT.Set(uint32(len(buf)))
|
||||
|
||||
i2c.BusT.TASKS_PREPARERX.Set(nrf.TWIS_TASKS_PREPARERX_TASKS_PREPARERX_Trigger)
|
||||
@@ -134,6 +139,10 @@ func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure buf stays alive until this point, so it won't be garbage
|
||||
// collected while it is used by the hardware.
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(buf)))
|
||||
|
||||
count = 0
|
||||
evt = I2CFinish
|
||||
err = nil
|
||||
@@ -163,7 +172,7 @@ func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err err
|
||||
|
||||
// Reply supplies the response data the controller.
|
||||
func (i2c *I2C) Reply(buf []byte) error {
|
||||
i2c.BusT.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
|
||||
i2c.BusT.TXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(buf)))))
|
||||
i2c.BusT.TXD.MAXCNT.Set(uint32(len(buf)))
|
||||
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
@@ -180,6 +189,10 @@ func (i2c *I2C) Reply(buf []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the buffer stays alive until this point, so it won't be garbage
|
||||
// collected while it is used by the hardware.
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(buf)))
|
||||
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -12,6 +12,8 @@ func CPUFrequency() uint32 {
|
||||
return 64000000
|
||||
}
|
||||
|
||||
var adcVDDHPin = Pin(254) // special pin number for VDDH on the nrf52840
|
||||
|
||||
// InitADC initializes the registers needed for ADC.
|
||||
func InitADC() {
|
||||
// Enable ADC.
|
||||
@@ -26,7 +28,7 @@ func InitADC() {
|
||||
// Samples can be 1(default), 2, 4, 8, 16, 32, 64, 128, 256 samples
|
||||
func (a *ADC) Configure(config ADCConfig) {
|
||||
var configVal uint32 = nrf.SAADC_CH_CONFIG_RESP_Bypass<<nrf.SAADC_CH_CONFIG_RESP_Pos |
|
||||
nrf.SAADC_CH_CONFIG_RESP_Bypass<<nrf.SAADC_CH_CONFIG_RESN_Pos |
|
||||
nrf.SAADC_CH_CONFIG_RESN_Bypass<<nrf.SAADC_CH_CONFIG_RESN_Pos |
|
||||
nrf.SAADC_CH_CONFIG_REFSEL_Internal<<nrf.SAADC_CH_CONFIG_REFSEL_Pos |
|
||||
nrf.SAADC_CH_CONFIG_MODE_SE<<nrf.SAADC_CH_CONFIG_MODE_Pos
|
||||
|
||||
@@ -116,36 +118,43 @@ func (a *ADC) Configure(config ADCConfig) {
|
||||
|
||||
// Get returns the current value of an ADC pin in the range 0..0xffff.
|
||||
func (a *ADC) Get() uint16 {
|
||||
var pwmPin uint32
|
||||
var adcPin uint32
|
||||
var rawValue volatile.Register16
|
||||
|
||||
switch a.Pin {
|
||||
case 2:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
|
||||
case 3:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
|
||||
case 4:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
|
||||
case 5:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
|
||||
case 28:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
|
||||
case 29:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
|
||||
case 30:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
|
||||
case 31:
|
||||
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
|
||||
adcPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
|
||||
case adcVDDHPin:
|
||||
if Device == "nrf52840" {
|
||||
adcPin = 0x0D // VDDHDIV5 on the nrf52840
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
||||
// Set pin to read.
|
||||
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
|
||||
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
|
||||
nrf.SAADC.CH[0].PSELP.Set(adcPin)
|
||||
|
||||
// Destination for sample result.
|
||||
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&rawValue))))
|
||||
// Note: rawValue doesn't need to be kept alive for the GC, since the
|
||||
// volatile read later will force it to stay alive.
|
||||
nrf.SAADC.RESULT.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(&rawValue))))
|
||||
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
|
||||
|
||||
// Start tasks.
|
||||
@@ -301,20 +310,18 @@ func (spi *SPI) Transfer(w byte) (byte, error) {
|
||||
// padded until they fit: if len(w) > len(r) the extra bytes received will be
|
||||
// dropped and if len(w) < len(r) extra 0 bytes will be sent.
|
||||
func (spi *SPI) Tx(w, r []byte) error {
|
||||
// Unfortunately the hardware (on the nrf52832) only supports up to 255
|
||||
// bytes in the buffers, so if either w or r is longer than that the
|
||||
// transfer needs to be broken up in pieces.
|
||||
// The nrf52840 supports far larger buffers however, which isn't yet
|
||||
// supported.
|
||||
// Unfortunately the hardware (on the nrf52832) only supports a limited
|
||||
// amount of bytes in the buffers (depending on the chip), so if either w or
|
||||
// r is longer than that the transfer needs to be broken up in pieces.
|
||||
for len(r) != 0 || len(w) != 0 {
|
||||
// Prepare the SPI transfer: set the DMA pointers and lengths.
|
||||
// read buffer
|
||||
nr := uint32(len(r))
|
||||
if nr > 0 {
|
||||
if nr > 255 {
|
||||
nr = 255
|
||||
if nr > spiMaxBufferSize {
|
||||
nr = spiMaxBufferSize
|
||||
}
|
||||
spi.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
|
||||
spi.Bus.RXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(r)))))
|
||||
r = r[nr:]
|
||||
}
|
||||
spi.Bus.RXD.MAXCNT.Set(nr)
|
||||
@@ -322,10 +329,10 @@ func (spi *SPI) Tx(w, r []byte) error {
|
||||
// write buffer
|
||||
nw := uint32(len(w))
|
||||
if nw > 0 {
|
||||
if nw > 255 {
|
||||
nw = 255
|
||||
if nw > spiMaxBufferSize {
|
||||
nw = spiMaxBufferSize
|
||||
}
|
||||
spi.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
|
||||
spi.Bus.TXD.PTR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(w)))))
|
||||
w = w[nw:]
|
||||
}
|
||||
spi.Bus.TXD.MAXCNT.Set(nw)
|
||||
@@ -335,10 +342,16 @@ func (spi *SPI) Tx(w, r []byte) error {
|
||||
// finished if the transfer is send-only (a common case).
|
||||
spi.Bus.TASKS_START.Set(1)
|
||||
for spi.Bus.EVENTS_END.Get() == 0 {
|
||||
gosched()
|
||||
}
|
||||
spi.Bus.EVENTS_END.Set(0)
|
||||
}
|
||||
|
||||
// Make sure the w and r buffers stay alive for the GC until this point,
|
||||
// since they are used by the hardware but not otherwise visible.
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(r)))
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(w)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,3 +7,7 @@ package machine
|
||||
func GetRNG() (ret uint32, err error) {
|
||||
return getRNG()
|
||||
}
|
||||
|
||||
func isSoftDeviceEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ import (
|
||||
|
||||
// avoid a heap allocation in GetRNG.
|
||||
var (
|
||||
softdeviceEnabled uint8
|
||||
bytesAvailable uint8
|
||||
buf [4]uint8
|
||||
bytesAvailable uint8
|
||||
buf [4]uint8
|
||||
|
||||
errNoSoftDeviceSupport = errors.New("rng: softdevice not supported on this device")
|
||||
errNotEnoughRandomData = errors.New("rng: not enough random data available")
|
||||
@@ -24,9 +23,7 @@ var (
|
||||
func GetRNG() (ret uint32, err error) {
|
||||
// First check whether the SoftDevice is enabled.
|
||||
// sd_rand_application_bytes_available_get cannot be called when the SoftDevice is not enabled.
|
||||
arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled
|
||||
|
||||
if softdeviceEnabled == 0 {
|
||||
if !isSoftDeviceEnabled() {
|
||||
return getRNG()
|
||||
}
|
||||
|
||||
@@ -57,3 +54,8 @@ func GetRNG() (ret uint32, err error) {
|
||||
|
||||
return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24, nil
|
||||
}
|
||||
|
||||
// This function is defined in the runtime, but we need it too.
|
||||
//
|
||||
//go:linkname isSoftDeviceEnabled runtime.isSoftDeviceEnabled
|
||||
func isSoftDeviceEnabled() bool
|
||||
|
||||
@@ -58,6 +58,10 @@ func machineInit() {
|
||||
|
||||
// Peripheral clocks should now all be running
|
||||
unresetBlockWait(RESETS_RESET_Msk)
|
||||
|
||||
// DBGPAUSE pauses the timer when a debugger is connected. This prevents
|
||||
// sleep functions from ever returning, so disable it.
|
||||
timer.setDbgPause(false)
|
||||
}
|
||||
|
||||
//go:linkname ticks runtime.machineTicks
|
||||
|
||||
@@ -128,7 +128,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
const ackTimeout = 570
|
||||
|
||||
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_ACK_REC)
|
||||
sendUSBPacket(0, []byte{}, 0)
|
||||
sendUSBPacket(0, []byte{})
|
||||
|
||||
// Wait for transfer to complete with a timeout.
|
||||
t := timer.timeElapsed()
|
||||
|
||||
@@ -131,7 +131,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
const ackTimeout = 570
|
||||
|
||||
rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_ACK_REC)
|
||||
sendUSBPacket(0, []byte{}, 0)
|
||||
sendUSBPacket(0, []byte{})
|
||||
|
||||
// Wait for transfer to complete with a timeout.
|
||||
t := timer.timeElapsed()
|
||||
|
||||
@@ -124,6 +124,31 @@ const (
|
||||
fnXIP pinFunc = 0
|
||||
)
|
||||
|
||||
// validPins confirms that the SPI pin selection is a legitimate one
|
||||
// for the the 2040 chip.
|
||||
func (spi *SPI) validPins(config SPIConfig) error {
|
||||
var okSDI, okSDO, okSCK bool
|
||||
switch spi.Bus {
|
||||
case rp.SPI0:
|
||||
okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20
|
||||
okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23
|
||||
okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22
|
||||
case rp.SPI1:
|
||||
okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28
|
||||
okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27
|
||||
okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26
|
||||
}
|
||||
switch {
|
||||
case !okSDI:
|
||||
return errSPIInvalidSDI
|
||||
case !okSDO:
|
||||
return errSPIInvalidSDO
|
||||
case !okSCK:
|
||||
return errSPIInvalidSCK
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Configure configures the gpio pin as per mode.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
if p == NoPin {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
package machine
|
||||
|
||||
import "device/rp"
|
||||
|
||||
// Analog pins on RP2350a.
|
||||
const (
|
||||
ADC0 Pin = GPIO26
|
||||
@@ -12,3 +14,28 @@ const (
|
||||
// fifth ADC channel.
|
||||
thermADC = 30
|
||||
)
|
||||
|
||||
// validPins confirms that the SPI pin selection is a legitimate one
|
||||
// for the the 2350a chip.
|
||||
func (spi *SPI) validPins(config SPIConfig) error {
|
||||
var okSDI, okSDO, okSCK bool
|
||||
switch spi.Bus {
|
||||
case rp.SPI0:
|
||||
okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20
|
||||
okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23
|
||||
okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22
|
||||
case rp.SPI1:
|
||||
okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28
|
||||
okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27
|
||||
okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26
|
||||
}
|
||||
switch {
|
||||
case !okSDI:
|
||||
return errSPIInvalidSDI
|
||||
case !okSDO:
|
||||
return errSPIInvalidSDO
|
||||
case !okSCK:
|
||||
return errSPIInvalidSCK
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
package machine
|
||||
|
||||
import "device/rp"
|
||||
|
||||
// RP2350B has additional pins.
|
||||
|
||||
const (
|
||||
@@ -46,3 +48,28 @@ var (
|
||||
PWM10 = getPWMGroup(10)
|
||||
PWM11 = getPWMGroup(11)
|
||||
)
|
||||
|
||||
// validPins confirms that the SPI pin selection is a legitimate one
|
||||
// for the the 2350b chip.
|
||||
func (spi *SPI) validPins(config SPIConfig) error {
|
||||
var okSDI, okSDO, okSCK bool
|
||||
switch spi.Bus {
|
||||
case rp.SPI0:
|
||||
okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 || config.SDI == 32 || config.SDI == 36
|
||||
okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 || config.SDO == 35 || config.SDO == 39
|
||||
okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 || config.SCK == 34 || config.SCK == 38
|
||||
case rp.SPI1:
|
||||
okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 || config.SDI == 40 || config.SDI == 44
|
||||
okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 || config.SDO == 31 || config.SDO == 43 || config.SDO == 47
|
||||
okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 || config.SCK == 30 || config.SCK == 42 || config.SCK == 46
|
||||
}
|
||||
switch {
|
||||
case !okSDI:
|
||||
return errSPIInvalidSDI
|
||||
case !okSDO:
|
||||
return errSPIInvalidSDO
|
||||
case !okSCK:
|
||||
return errSPIInvalidSCK
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -100,7 +100,8 @@ func ReadTemperature() (millicelsius int32) {
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
|
||||
// T = 27 - (ADC_voltage - 0.706)/0.001721
|
||||
return (27000<<16 - (int32(thermChan.getVoltage())-706<<16)*581) >> 16
|
||||
// 1/0.001721 ≈ 581
|
||||
return int32(((int64(27000) << 16) - ((int64(thermChan.getVoltage()) - (int64(706) << 16)) * 581)) >> 16)
|
||||
}
|
||||
|
||||
// waitForReady spins waiting for the ADC peripheral to become ready.
|
||||
|
||||
@@ -108,7 +108,7 @@ func (spi *SPI) SetBaudRate(br uint32) error {
|
||||
var prescale, postdiv uint32
|
||||
freq := CPUFrequency()
|
||||
for prescale = 2; prescale < 255; prescale += 2 {
|
||||
if freq < (prescale+2)*256*br {
|
||||
if uint64(freq) < uint64((prescale+2)*256)*uint64(br) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -165,27 +165,9 @@ func (spi *SPI) Configure(config SPIConfig) error {
|
||||
config.SDI = SPI1_SDI_PIN
|
||||
}
|
||||
}
|
||||
var okSDI, okSDO, okSCK bool
|
||||
switch spi.Bus {
|
||||
case rp.SPI0:
|
||||
okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20
|
||||
okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23
|
||||
okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22
|
||||
case rp.SPI1:
|
||||
okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28
|
||||
okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27
|
||||
okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26
|
||||
if err := spi.validPins(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case !okSDI:
|
||||
return errSPIInvalidSDI
|
||||
case !okSDO:
|
||||
return errSPIInvalidSDO
|
||||
case !okSCK:
|
||||
return errSPIInvalidSCK
|
||||
}
|
||||
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = defaultBaud
|
||||
}
|
||||
@@ -309,7 +291,7 @@ func (spi *SPI) tx(tx []byte) error {
|
||||
// - set data size to single bytes
|
||||
// - set the DREQ so that the DMA will fill the SPI FIFO as needed
|
||||
// - start the transfer
|
||||
ch.READ_ADDR.Set(uint32(uintptr(unsafe.Pointer(&tx[0]))))
|
||||
ch.READ_ADDR.Set(uint32(unsafeNoEscape(unsafe.Pointer(unsafe.SliceData(tx)))))
|
||||
ch.WRITE_ADDR.Set(uint32(uintptr(unsafe.Pointer(&spi.Bus.SSPDR))))
|
||||
ch.TRANS_COUNT.Set(uint32(len(tx)))
|
||||
ch.CTRL_TRIG.Set(rp.DMA_CH0_CTRL_TRIG_INCR_READ |
|
||||
@@ -328,6 +310,11 @@ func (spi *SPI) tx(tx []byte) error {
|
||||
for ch.CTRL_TRIG.Get()&rp.DMA_CH0_CTRL_TRIG_BUSY != 0 {
|
||||
}
|
||||
|
||||
// Make sure the read buffer stays alive until this point (in the unlikely
|
||||
// case the tx slice wasn't read after this function returns and a GC cycle
|
||||
// happened inbetween).
|
||||
keepAliveNoEscape(unsafe.Pointer(unsafe.SliceData(tx)))
|
||||
|
||||
// We didn't read any result values, which means the RX FIFO has likely
|
||||
// overflown. We have to clean up this mess now.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user