mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 14:48:40 +00:00
Compare commits
307 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d01d85930d | |||
| ac821d8295 | |||
| 5c2753e54e | |||
| 0212f0c008 | |||
| f5f4751088 | |||
| 62fb386d57 | |||
| a59f92daf8 | |||
| b7508818ee | |||
| 284e1acd87 | |||
| 37849c4897 | |||
| 213e73ad84 | |||
| 4a240827cb | |||
| 92d9f856ab | |||
| ee5890f36f | |||
| 744574193b | |||
| bbe755fb69 | |||
| 635d322703 | |||
| ee90bdebff | |||
| bcdb3fc681 | |||
| b7b23ace3f | |||
| f366cd53b7 | |||
| da81784ee9 | |||
| 481f60c5ea | |||
| cf39db36fe | |||
| 54c07b7de8 | |||
| 2fb866ca86 | |||
| 4d11d552db | |||
| b43bd9e62a | |||
| 572c22f66a | |||
| 1b66da4dff | |||
| b08ff17f6b | |||
| 41e787d504 | |||
| 6dba16f28e | |||
| b336a1561f | |||
| 4c682680ca | |||
| af76c807e2 | |||
| cdbd850f80 | |||
| d256804af7 | |||
| e3c96803c3 | |||
| f55bb8e030 | |||
| 07fb3a0cad | |||
| 02913563df | |||
| 535e64adbc | |||
| af936f3261 | |||
| d1a45f2efc | |||
| b56a263d0d | |||
| 6435f62dcc | |||
| f4c8c37b7b | |||
| 868812717f | |||
| e82f595f37 | |||
| e5af121553 | |||
| 20fdbc1f9d | |||
| 14fed59827 | |||
| d331aca296 | |||
| 7e8a2e8934 | |||
| e7363966a5 | |||
| 373ab34492 | |||
| 602f35a5ca | |||
| 1d5c5ca2ef | |||
| 90935703e6 | |||
| d8ee520bdc | |||
| e4da35486b | |||
| 4e41e9084a | |||
| ee3af40cab | |||
| 666312f63f | |||
| ccfe92a58c | |||
| 4fa6a132e2 | |||
| 1a67795fd3 | |||
| c70daa2497 | |||
| d28b58e4dd | |||
| 25b03414dc | |||
| 2ab7ee6a8a | |||
| 6a2dd35fe6 | |||
| 4c0fbbfc7f | |||
| 36bd66a858 | |||
| 9d7dd3dd4b | |||
| 9bf5d6a4aa | |||
| 839edec64c | |||
| 7e05c92420 | |||
| 0b2aec1164 | |||
| ae381e74a5 | |||
| 3392827c3e | |||
| 59838338ba | |||
| 76303f9db4 | |||
| 4bf8b618e5 | |||
| c89a684ad2 | |||
| 7aac1a1391 | |||
| af9f19615b | |||
| 79b63dd041 | |||
| 06e34caa5f | |||
| 4e9f9e2773 | |||
| 64957c5254 | |||
| 1bba5f5d7b | |||
| 48ef68dd86 | |||
| 8b9bee4cad | |||
| b4c9b579b8 | |||
| 2b1dc4fee5 | |||
| 0244bed033 | |||
| 60b23a7035 | |||
| 4326c8f10e | |||
| 1672610749 | |||
| e00a2395d9 | |||
| 42175496eb | |||
| 3b4e543f4e | |||
| ad3e9e1a77 | |||
| e0385e48d0 | |||
| feadb9c85c | |||
| 4bf7308d26 | |||
| 19e4db45db | |||
| 71b44e79b3 | |||
| 9e97566b5f | |||
| 7d83e76833 | |||
| 9e7882b1b7 | |||
| 0c4f9d1f19 | |||
| a85cb22193 | |||
| 60bb832c89 | |||
| 6eda52a289 | |||
| 8badf79af9 | |||
| 66d3c4edb8 | |||
| 63aaa43072 | |||
| ee81c31884 | |||
| 50d681359d | |||
| d50c54fce0 | |||
| 4a81cac53b | |||
| 84a3273131 | |||
| 9182664845 | |||
| a2f95d6b87 | |||
| 698b1f19c6 | |||
| e6ccdd9d1a | |||
| b39a982067 | |||
| e0bf376068 | |||
| b044d4ff3d | |||
| 0cd93a3a9e | |||
| 5faff2e13a | |||
| 195de23d3b | |||
| d4bdd836bc | |||
| a11f2436e3 | |||
| 017ab4c352 | |||
| 181d2ad2b4 | |||
| 53b95cad08 | |||
| e7bd22edf2 | |||
| 1a60a1f526 | |||
| 3fbd3c4d93 | |||
| 1213a45197 | |||
| 4e4e4eee04 | |||
| bf20c652e2 | |||
| a3afd4e8ac | |||
| cb9c6f0074 | |||
| 5fee3428bc | |||
| 464ebc4fe1 | |||
| 568c2a4363 | |||
| c611c72526 | |||
| dfb8c996a1 | |||
| 85da9a0aac | |||
| 17bc0d6663 | |||
| 31043628d8 | |||
| 2c0f61cad1 | |||
| 97ece754f6 | |||
| 39f76f43fc | |||
| f239e8e2d9 | |||
| 6b73b5e486 | |||
| 855e12df51 | |||
| 0b6bb12e9e | |||
| 72c7adf94a | |||
| 13fb5aa7e7 | |||
| a3fdbec13d | |||
| 360f6904f5 | |||
| 7201b13085 | |||
| 9c0bf8bd2c | |||
| 63c7a41337 | |||
| c0f8f129c0 | |||
| adaa7ca27a | |||
| a5ddc68845 | |||
| f7880e73d8 | |||
| 3aa8c8e0d1 | |||
| 6cb7f29d9b | |||
| 21527353f7 | |||
| bedd27b20e | |||
| 3612b7749e | |||
| 45c916f5c0 | |||
| 688a5dbf8d | |||
| 35dcf135c0 | |||
| c482d65397 | |||
| d73e12db63 | |||
| 4b0e56cbec | |||
| 62e1c3ebb7 | |||
| a4a1001dd3 | |||
| e8f6df928c | |||
| f180339d6b | |||
| 5ed0cecf0d | |||
| 523c6c0e3b | |||
| 17f5fb1071 | |||
| 4d43df75d5 | |||
| 57b0c21492 | |||
| 8fb5877d9e | |||
| 6fbe6fa2ae | |||
| 24b4dc31a4 | |||
| 4f8127d0bf | |||
| e0329b25de | |||
| 229f479a7d | |||
| 876f08979f | |||
| f2cc98caa5 | |||
| 0d65b4dd26 | |||
| 6a685b2a8d | |||
| 569817a514 | |||
| 7a96f0f609 | |||
| 821227a03b | |||
| 5b42871baa | |||
| c5598630c9 | |||
| 6c40ee93fe | |||
| 4acb1a5845 | |||
| e0f3333cc3 | |||
| af247e27ff | |||
| ec3a4da4df | |||
| 905269bf11 | |||
| e4f29ae2f9 | |||
| 7fb23824e2 | |||
| f8a6e662d8 | |||
| 0ddd65658e | |||
| db08b5aaa5 | |||
| 383e7ae14a | |||
| 4f7864b757 | |||
| 833c91fceb | |||
| 344e493ac8 | |||
| 1626b50457 | |||
| 93fb897feb | |||
| 15109a2924 | |||
| d9c6f7c11f | |||
| fa4f361ca7 | |||
| 9f02340a26 | |||
| c6728643e6 | |||
| e849901ad6 | |||
| 91d6ca057c | |||
| 0da97e2427 | |||
| ac36f232bc | |||
| 94a54bc105 | |||
| b044d27dff | |||
| 6768af91e7 | |||
| a366c014c7 | |||
| 584a2718d0 | |||
| 069c397975 | |||
| e0aee1f23c | |||
| ad9f790dfc | |||
| f42d8b3056 | |||
| 04412cba0e | |||
| 3b2763896f | |||
| fb394c7685 | |||
| a52cad3825 | |||
| 0e94553b26 | |||
| e6580bfff4 | |||
| 5db83f11df | |||
| 60366adfa8 | |||
| faa449a9e1 | |||
| 08cf2b25c5 | |||
| d6103222f7 | |||
| 69e5c5088d | |||
| a6084767b3 | |||
| cf4a6d3253 | |||
| 4716298044 | |||
| 7706c41bf6 | |||
| 0bc19735f3 | |||
| 51c1579c3d | |||
| 6a45b73fcb | |||
| 2de64d3f4e | |||
| c192c7376e | |||
| 2a821d2a66 | |||
| 90af41d089 | |||
| 7654d86d2c | |||
| 45f119de34 | |||
| 71be24e4f9 | |||
| 3701e6eac1 | |||
| 0463d34887 | |||
| 0b47b99448 | |||
| ea97c60959 | |||
| de281191e0 | |||
| fc28f513c7 | |||
| 34ba0c1be1 | |||
| 7ca45d61fc | |||
| 871cd66b98 | |||
| 192a55970f | |||
| 8babc47638 | |||
| 1cb702ac4c | |||
| c6ac1cc969 | |||
| 0ce539ad42 | |||
| 930255ff46 | |||
| 57ecf1acdc | |||
| 313c9e31dd | |||
| d87e3ce330 | |||
| 11a6c84ea5 | |||
| 1d86b3f425 | |||
| f9b6f8339b | |||
| 0ff243e5e2 | |||
| 79930a209c | |||
| bbc79ee40a | |||
| 960a0b79bf | |||
| e4ef6f85ac | |||
| 3a3de8a778 | |||
| ca823f9a0d | |||
| 4ec1e58aa6 | |||
| d98c0afbab | |||
| 12e3d1d81d | |||
| a7e3cf0826 | |||
| 43a4b256bd | |||
| 5cc5f11b58 | |||
| 836689fdd2 | |||
| 9b86080c80 | |||
| 517098c468 |
@@ -87,6 +87,8 @@ jobs:
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
run: make wasi-libc
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
- name: Test TinyGo
|
||||
shell: bash
|
||||
run: make test GOTESTFLAGS="-short"
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
tinygo/tinygo-dev
|
||||
ghcr.io/${{ github.repository }}/tinygo-dev
|
||||
ghcr.io/${{ github.repository_owner }}/tinygo-dev
|
||||
tags: |
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
|
||||
@@ -275,7 +275,7 @@ jobs:
|
||||
# in that process to avoid doing lots of duplicate work and to avoid
|
||||
# complications around precompiled libraries such as compiler-rt shipped as
|
||||
# part of the release tarball.
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -391,7 +391,7 @@ jobs:
|
||||
# in that process to avoid doing lots of duplicate work and to avoid
|
||||
# complications around precompiled libraries such as compiler-rt shipped as
|
||||
# part of the release tarball.
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# This is the Github action to build and push the LLVM Docker image
|
||||
# used by the tinygo/tinygo-dev Docker image.
|
||||
#
|
||||
# It only needs to be rebuilt when updating the LLVM version.
|
||||
#
|
||||
# To update, make any needed changes to this file,
|
||||
# then push to the "build-llvm-image" branch.
|
||||
#
|
||||
# The needed image will be rebuilt, which will very likely take at least 1-2 hours.
|
||||
name: LLVM
|
||||
on:
|
||||
push:
|
||||
branches: [ build-llvm-image ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-push-llvm:
|
||||
name: build-push-llvm
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
tinygo/llvm-15
|
||||
ghcr.io/${{ github.repository_owner }}/llvm-15
|
||||
tags: |
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
target: tinygo-llvm-build
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Binary size difference
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
sizediff:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
# Prepare, install tools
|
||||
- name: Add GOBIN to $PATH
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
llvm-15-dev \
|
||||
clang-15 \
|
||||
libclang-15-dev \
|
||||
lld-15
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-15-sizediff-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- run: make gen-device -j4
|
||||
- name: Download drivers repo
|
||||
run: git clone https://github.com/tinygo-org/drivers.git
|
||||
- name: Save HEAD
|
||||
run: git branch github-actions-saved-HEAD HEAD
|
||||
|
||||
# Compute sizes for the dev branch
|
||||
- name: Checkout dev branch
|
||||
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||
- name: Build tinygo binary for the dev branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the dev branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||
|
||||
# Compute sizes for the PR branch
|
||||
- name: Checkout PR branch
|
||||
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
|
||||
- name: Build tinygo binary for the PR branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the PR branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
||||
|
||||
# Create comment
|
||||
# TODO: add a summary, something like:
|
||||
# - overall size difference (percent)
|
||||
# - number of binaries that grew / shrank / remained the same
|
||||
# - don't show the full diff when no binaries changed
|
||||
- name: Calculate size diff
|
||||
run: ./tools/sizediff drivers/sizes-dev.txt drivers/sizes-pr.txt | tee sizediff.txt
|
||||
- name: Create comment
|
||||
run: |
|
||||
echo "Size difference with the dev branch:" > comment.txt
|
||||
echo "<details><summary>Binary size difference</summary>" >> comment.txt
|
||||
echo "<pre>" >> comment.txt
|
||||
cat sizediff.txt >> comment.txt
|
||||
echo "</pre></details>" >> comment.txt
|
||||
- name: Comment contents
|
||||
run: cat comment.txt
|
||||
- name: Add comment
|
||||
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
|
||||
uses: thollander/actions-comment-pull-request@v2.3.1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
filePath: comment.txt
|
||||
comment_tag: sizediff
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
uses: actions/cache/restore@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-15-windows-v5
|
||||
key: llvm-build-15-windows-v6
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -97,6 +97,8 @@ jobs:
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
scoop install wasmtime
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
- name: Test TinyGo
|
||||
shell: bash
|
||||
run: make test GOTESTFLAGS="-short"
|
||||
|
||||
+140
-3
@@ -1,3 +1,140 @@
|
||||
0.28.0
|
||||
---
|
||||
|
||||
* **general**
|
||||
- fix parallelism in the compiler on Windows by building LLVM with thread support
|
||||
- support qemu-user debugging
|
||||
- make target JSON msd-volume-name an array
|
||||
- print source location when a panic happens in -monitor
|
||||
- `test`: don't print `ok` for a successful compile-only
|
||||
* **compiler**
|
||||
- `builder`: remove non-ThinLTO build mode
|
||||
- `builder`: fail earlier if Go is not available
|
||||
- `builder`: improve `-size=full` in a number of ways
|
||||
- `builder`: implement Nordic DFU file writer in Go
|
||||
- `cgo`: allow `LDFLAGS: --export=...`
|
||||
- `compiler`: support recursive slice types
|
||||
- `compiler`: zero struct padding during map operations
|
||||
- `compiler`: add llvm.ident metadata
|
||||
- `compiler`: remove `unsafe.Pointer(uintptr(v) + idx)` optimization (use `unsafe.Add` instead)
|
||||
- `compiler`: add debug info to `//go:embed` data structures for better `-size` output
|
||||
- `compiler`: add debug info to string constants
|
||||
- `compiler`: fix a minor race condition
|
||||
- `compiler`: emit correct alignment in debug info for global variables
|
||||
- `compiler`: correctly generate reflect data for local named types
|
||||
- `compiler`: add alloc attributes to `runtime.alloc`, reducing flash usage slightly
|
||||
- `compiler`: for interface maps, use the original named type if available
|
||||
- `compiler`: implement most math/bits functions as LLVM intrinsics
|
||||
- `compiler`: ensure all defers have been seen before creating rundefers
|
||||
* **standard library**
|
||||
- `internal/task`: disallow blocking inside an interrupt
|
||||
- `machine`: add `CPUReset`
|
||||
- `machine/usb/hid`: add MediaKey support
|
||||
- `machine/usb/hid/joystick`: move joystick under HID
|
||||
- `machine/usb/hid/joystick`: allow joystick settings override
|
||||
- `machine/usb/hid/joystick`: handle case where we cannot find the correct HID descriptor
|
||||
- `machine/usb/hid/mouse`: add support for mouse back and forward
|
||||
- `machine/usb`: add ability to override default VID, PID, manufacturer name, and product name
|
||||
- `net`: added missing `TCPAddr` and `UDPAddr` implementations
|
||||
- `os`: add IsTimeout function
|
||||
- `os`: fix resource leak in `(*File).Close`
|
||||
- `os`: add `(*File).Sync`
|
||||
- `os`: implement `(*File).ReadDir` for wasi
|
||||
- `os`: implement `(*File).WriteAt`
|
||||
- `reflect`: make sure null bytes are supported in tags
|
||||
- `reflect`: refactor this package to enable many new features
|
||||
- `reflect`: add map type methods: `Elem` and `Key`
|
||||
- `reflect`: add map methods: `MapIndex`, `MapRange`/`MapIter`, `SetMapIndex`, `MakeMap`, `MapKeys`
|
||||
- `reflect`: add slice methods: `Append`, `MakeSlice`, `Slice`, `Slice3`, `Copy`, `Bytes`, `SetLen`
|
||||
- `reflect`: add misc methods: `Zero`, `Addr`, `UnsafeAddr`, `OverflowFloat`, `OverflowInt`, `OverflowUint`, `SetBytes`, `Convert`, `CanInt`, `CanFloat`, `CanComplex`, `Comparable`
|
||||
- `reflect`: add type methods: `String`, `PkgPath`, `FieldByName`, `FieldByIndex`, `NumMethod`
|
||||
- `reflect`: add stubs for `Type.Method`, `CanConvert`, `ArrayOf`, `StructOf`, `MapOf`
|
||||
- `reflect`: add stubs for channel select routines/types
|
||||
- `reflect`: allow nil rawType to call Kind()
|
||||
- `reflect`: ensure all ValueError panics have Kind fields
|
||||
- `reflect`: add support for named types
|
||||
- `reflect`: improve `Value.String()`
|
||||
- `reflect`: set `Index` and `PkgPath` field in `Type.Field`
|
||||
- `reflect`: `Type.AssignableTo`: you can assign anything to `interface{}`
|
||||
- `reflect`: add type check to `Value.Field`
|
||||
- `reflect`: let `TypeOf(nil)` return nil
|
||||
- `reflect`: move `StructField.Anonymous` field to match upstream location
|
||||
- `reflect`: add `UnsafePointer` for Func types
|
||||
- `reflect`: `MapIter.Next` needs to allocate new keys/values every time
|
||||
- `reflect`: fix `IsNil` for interfaces
|
||||
- `reflect`: fix `Type.Name` to return an empty string for non-named types
|
||||
- `reflect`: add `VisibleFields`
|
||||
- `reflect`: properly handle embedded structs
|
||||
- `reflect`: make sure `PointerTo` works for named types
|
||||
- `reflect`: `Set`: convert non-interface to interface
|
||||
- `reflect`: `Set`: fix direction of assignment check
|
||||
- `reflect`: support channel directions
|
||||
- `reflect`: print struct tags in Type.String()
|
||||
- `reflect`: properly handle read-only values
|
||||
- `runtime`: allow custom-gc SetFinalizer and clarify KeepAlive
|
||||
- `runtime`: implement KeepAlive using inline assembly
|
||||
- `runtime`: check for heap allocations inside interrupts
|
||||
- `runtime`: properly turn pointer into empty interface when hashing
|
||||
- `runtime`: improve map size hint usage
|
||||
- `runtime`: zero map key/value on deletion to so GC doesn't see them
|
||||
- `runtime`: print the address where a panic happened
|
||||
- `runtime/debug`: stub `SetGCPercent`, `BuildInfo.Settings`
|
||||
- `runtime/metrics`: add this package as a stub
|
||||
- `syscall`: `Stat_t` timespec fields are Atimespec on darwin
|
||||
- `syscall`: add `Timespec.Unix()` for wasi
|
||||
- `syscall`: add fsync using libc
|
||||
- `testing`: support -test.count
|
||||
- `testing`: make test output unbuffered when verbose
|
||||
- `testing`: add -test.skip
|
||||
- `testing`: move runtime.GC() call to runN to match upstream
|
||||
- `testing`: add -test.shuffle to order randomize test and benchmark order
|
||||
* **targets**
|
||||
- `arm64`: fix register save/restore to include vector registers
|
||||
- `attiny1616`: add support for this chip
|
||||
- `cortexm`: refactor EnableInterrupts and DisableInterrupts to avoid `arm.AsmFull`
|
||||
- `cortexm`: enable functions in RAM for go & cgo
|
||||
- `cortexm`: convert SystemStack from `AsmFull` to C inline assembly
|
||||
- `cortexm`: fix crash due to wrong stack size offset
|
||||
- `nrf`: samd21, stm32: add flash API
|
||||
- `nrf`: fix memory issue in ADC read
|
||||
- `nrf`: new peripheral type for nrf528xx chips
|
||||
- `nrf`: implement target mode
|
||||
- `nrf`: improve ADC and add oversampling, longer sample time, and reference voltage
|
||||
- `rp2040`: change calling order for device enumeration fix to do first
|
||||
- `rp2040`: rtc delayed interrupt
|
||||
- `rp2040`: provide better errors for invalid pins on I2C and SPI
|
||||
- `rp2040`: change uart to allow for a single pin
|
||||
- `rp2040`: implement Flash interface
|
||||
- `rp2040`: remove SPI `DataBits` property
|
||||
- `rp2040`: unify all linker scripts using LDFLAGS
|
||||
- `rp2040`: remove SPI deadline for improved performance
|
||||
- `rp2040`: use 4MHz as default frequency for SPI
|
||||
- `rp2040`: implement target mode
|
||||
- `rp2040`: use DMA for send-only SPI transfers
|
||||
- `samd21`: rearrange switch case for get pin cfg
|
||||
- `samd21`: fix issue with WS2812 driver by making pin accesses faster
|
||||
- `samd51`: enable CMCC cache for greatly improved performance
|
||||
- `samd51`: remove extra BK0RDY clear
|
||||
- `samd51`: implement Flash interface
|
||||
- `samd51`: use correct SPI frequency
|
||||
- `samd51`: remove extra BK0RDY clear
|
||||
- `samd51`: fix ADC multisampling
|
||||
- `wasi`: allow users to set the `runtime_memhash_tsip` or `runtime_memhash_fnv` build tags
|
||||
- `wasi`: set `WASMTIME_BACKTRACE_DETAILS` when running in wasmtime.
|
||||
- `wasm`: implement the `//go:wasmimport` directive
|
||||
* **boards**
|
||||
- `gameboy-advance`: switch to use register definitions in device/gba
|
||||
- `gameboy-advance`: rename display and make pointer receivers
|
||||
- `gopher-badge`: Added Gopher Badge support
|
||||
- `lorae5`: add needed definition for UART2
|
||||
- `lorae5`: correct mapping for I2C bus, add pin mapping to enable power
|
||||
- `pinetime`: update the target file (rename from pinetime-devkit0)
|
||||
- `qtpy`: fix bad pin assignment
|
||||
- `wioterminal`: fix pin definition of BCM13
|
||||
- `xiao`: Pins D4 & D5 are I2C1. Use pins D2 & D3 for I2C0.
|
||||
- `xiao`: add DefaultUART
|
||||
|
||||
|
||||
0.27.0
|
||||
---
|
||||
|
||||
@@ -416,7 +553,7 @@
|
||||
- `interp`: always run atomic and volatile loads/stores at runtime
|
||||
- `interp`: bump timeout to 180 seconds
|
||||
- `interp`: handle type assertions on nil interfaces
|
||||
- `loader`: elminate goroot cache inconsistency
|
||||
- `loader`: eliminate goroot cache inconsistency
|
||||
- `loader`: respect $GOROOT when running `go list`
|
||||
- `transform`: allocate the correct amount of bytes in an alloca
|
||||
- `transform`: remove switched func lowering
|
||||
@@ -1115,7 +1252,7 @@
|
||||
- `sync`: add WaitGroup
|
||||
* **targets**
|
||||
- `arm`: allow nesting in DisableInterrupts and EnableInterrupts
|
||||
- `arm`: make FPU configuraton consistent
|
||||
- `arm`: make FPU configuration consistent
|
||||
- `arm`: do not mask fault handlers in critical sections
|
||||
- `atmega2560`: fix pin mapping for pins D2, D5 and the L port
|
||||
- `atsamd`: return an error when an incorrect PWM pin is used
|
||||
@@ -1144,7 +1281,7 @@
|
||||
- `nrf`: add microbit-s110v8 target
|
||||
- `nrf`: fix bug in SPI.Tx
|
||||
- `nrf`: support debugging the PCA10056
|
||||
- `pygamer`: add Adafruit PyGamer suport
|
||||
- `pygamer`: add Adafruit PyGamer support
|
||||
- `riscv`: fix interrupt configuration bug
|
||||
- `riscv`: disable linker relaxations during gp init
|
||||
- `stm32f4disco`: add new target with ST-Link v2.1 debugger
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of the Go standard library.
|
||||
Copyright (c) 2009-2022 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2009-2023 The Go Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
|
||||
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
@@ -120,10 +120,8 @@ ifeq ($(OS),Windows_NT)
|
||||
START_GROUP = -Wl,--start-group
|
||||
END_GROUP = -Wl,--end-group
|
||||
|
||||
# LLVM compiled using MinGW on Windows appears to have problems with threads.
|
||||
# Without this flag, linking results in errors like these:
|
||||
# libLLVMSupport.a(Threading.cpp.obj):Threading.cpp:(.text+0x55): undefined reference to `std::thread::hardware_concurrency()'
|
||||
LLVM_OPTION += -DLLVM_ENABLE_THREADS=OFF -DLLVM_ENABLE_PIC=OFF
|
||||
# PIC needs to be disabled for libclang to work.
|
||||
LLVM_OPTION += -DLLVM_ENABLE_PIC=OFF
|
||||
|
||||
CGO_CPPFLAGS += -DCINDEX_NO_EXPORTS
|
||||
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
@@ -281,6 +279,7 @@ TEST_PACKAGES_SLOW = \
|
||||
|
||||
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
|
||||
TEST_PACKAGES_FAST = \
|
||||
compress/lzw \
|
||||
compress/zlib \
|
||||
container/heap \
|
||||
container/list \
|
||||
@@ -309,7 +308,6 @@ TEST_PACKAGES_FAST = \
|
||||
internal/profile \
|
||||
math \
|
||||
math/cmplx \
|
||||
net \
|
||||
net/http/internal/ascii \
|
||||
net/mail \
|
||||
os \
|
||||
@@ -334,7 +332,6 @@ endif
|
||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
||||
# bytes requires mmap
|
||||
# compress/flate appears to hang on wasi
|
||||
# compress/lzw appears to hang on wasi
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# image requires recover(), which is not yet supported on wasi
|
||||
@@ -350,13 +347,13 @@ TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
bytes \
|
||||
compress/flate \
|
||||
compress/lzw \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
image \
|
||||
io/ioutil \
|
||||
mime/quotedprintable \
|
||||
net \
|
||||
strconv \
|
||||
testing/fstest \
|
||||
text/tabwriter \
|
||||
@@ -366,7 +363,6 @@ TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
|
||||
TEST_PACKAGES_WINDOWS := \
|
||||
compress/flate \
|
||||
compress/lzw \
|
||||
crypto/hmac \
|
||||
strconv \
|
||||
text/template/parse \
|
||||
@@ -486,6 +482,8 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
@@ -530,6 +528,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=bluemicro840 examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
|
||||
@@ -566,7 +566,7 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=pinetime examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -640,6 +640,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -704,6 +706,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=attiny1616 examples/empty
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
|
||||
@@ -717,6 +721,8 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
[](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
|
||||
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
|
||||
|
||||
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
|
||||
|
||||
## Embedded
|
||||
|
||||
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
|
||||
|
||||
```go
|
||||
@@ -35,115 +37,62 @@ The above program can be compiled and run without modification on an Arduino Uno
|
||||
tinygo flash -target arduino examples/blinky1
|
||||
```
|
||||
|
||||
## WebAssembly
|
||||
|
||||
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
|
||||
|
||||
TinyGo programs can run in Fastly Compute@Edge (https://developer.fastly.com/learning/compute/go/), Fermyon Spin (https://developer.fermyon.com/spin/go-components), wazero (https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
||||
|
||||
Here is a small TinyGo program for use by a WASI host application:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
//go:wasm-module yourmodulename
|
||||
//export add
|
||||
func add(x, y uint32) uint32 {
|
||||
return x + y
|
||||
}
|
||||
|
||||
// main is required for the `wasi` target, even if it isn't used.
|
||||
func main() {}
|
||||
```
|
||||
|
||||
This compiles the above TinyGo program for use on any WASI runtime:
|
||||
|
||||
```shell
|
||||
tinygo build -o main.wasm -target=wasi main.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
See the [getting started instructions](https://tinygo.org/getting-started/) for information on how to install TinyGo, as well as how to run the TinyGo compiler using our Docker container.
|
||||
|
||||
## Supported boards/targets
|
||||
## Supported targets
|
||||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
### Embedded
|
||||
|
||||
The following 94 microcontroller boards are currently supported:
|
||||
You can compile TinyGo programs for over 94 different microcontroller boards.
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
* [Adafruit CLUE](https://www.adafruit.com/product/4500)
|
||||
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
|
||||
* [Adafruit Feather M0 Express](https://www.adafruit.com/product/3403)
|
||||
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
||||
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||
* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516)
|
||||
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
|
||||
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
||||
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
|
||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
||||
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
||||
* [Adafruit KB2040](https://www.adafruit.com/product/5302)
|
||||
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
|
||||
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
|
||||
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
|
||||
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
|
||||
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
|
||||
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
||||
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
||||
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
|
||||
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
|
||||
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
||||
* [Arduino MKR WiFi 1010](https://store.arduino.cc/usa/mkr-wifi-1010)
|
||||
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
||||
* [Arduino Nano 33 BLE](https://store.arduino.cc/nano-33-ble)
|
||||
* [Arduino Nano 33 BLE Sense](https://store.arduino.cc/nano-33-ble-sense)
|
||||
* [Arduino Nano 33 IoT](https://store.arduino.cc/nano-33-iot)
|
||||
* [Arduino Nano RP2040 Connect](https://store.arduino.cc/nano-rp2040-connect)
|
||||
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||
* [BBC micro:bit](https://microbit.org/)
|
||||
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
|
||||
* [blues wireless Swan](https://blues.io/products/swan/)
|
||||
* [Digispark](http://digistump.com/products/1)
|
||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
|
||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
* [iLabs Challenger RP2040 LoRa](https://ilabs.se/product/challenger-rp2040-lora/)
|
||||
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
||||
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
||||
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
||||
* [MCH2022 badge](https://badge.team/docs/badges/mch2022/)
|
||||
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
||||
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
|
||||
* [Nintendo Switch](https://www.nintendo.com/switch/)
|
||||
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
||||
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
||||
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
|
||||
* [Nordic Semiconductor pca10059](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
|
||||
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
|
||||
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
|
||||
* [Pimoroni Tufty2040](https://shop.pimoroni.com/products/tufty-2040)
|
||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
||||
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
|
||||
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
||||
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
||||
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
|
||||
* [Seeed XIAO ESP32C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
|
||||
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
|
||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
|
||||
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
|
||||
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
||||
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
|
||||
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
|
||||
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
|
||||
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
|
||||
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
||||
* [ST Micro STM32F469 "Discovery"](https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/32f469idiscovery.html)
|
||||
* [The Things Industries Generic Node Sensor Edition](https://www.genericnode.com/docs/sensor-edition/)
|
||||
* [Waveshare RP2040-Zero](https://www.waveshare.com/wiki/RP2040-Zero)
|
||||
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
|
||||
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
|
||||
|
||||
### WebAssembly
|
||||
|
||||
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
|
||||
TinyGo programs can be compiled for both WASM and WASI targets.
|
||||
|
||||
For more information, see https://tinygo.org/docs/guides/webassembly/
|
||||
|
||||
### Operating Systems
|
||||
|
||||
You can also compile programs for Linux, macOS, and Windows targets.
|
||||
|
||||
For more information:
|
||||
|
||||
- Linux https://tinygo.org/docs/guides/linux/
|
||||
|
||||
- macOS https://tinygo.org/docs/guides/macos/
|
||||
|
||||
- Windows https://tinygo.org/docs/guides/windows/
|
||||
|
||||
## Currently supported features:
|
||||
|
||||
|
||||
+2
-7
@@ -175,7 +175,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
Debug: true,
|
||||
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
||||
}
|
||||
|
||||
// Load the target machine, which is the LLVM object that contains all
|
||||
@@ -909,13 +909,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
case "nrf-dfu":
|
||||
// special format for nrfutil for Nordic chips
|
||||
tmphexpath := filepath.Join(tmpdir, "main.hex")
|
||||
err := objcopy(result.Executable, tmphexpath, "hex")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err = makeDFUFirmwareImage(config.Options, tmphexpath, result.Binary)
|
||||
err = makeDFUFirmwareImage(config.Options, result.Executable, result.Binary)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||
}
|
||||
if major != 1 || minor < 18 || minor > 20 {
|
||||
// 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.18 through 1.20, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ type espImageSegment struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
|
||||
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
|
||||
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
||||
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||
//
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
numRunningJobs--
|
||||
<-sema
|
||||
if jobRunnerDebug {
|
||||
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
|
||||
fmt.Println("## finished:", completed.description, "(time "+completed.duration.String()+")")
|
||||
}
|
||||
if completed.err != nil {
|
||||
// Wait for any current jobs to finish.
|
||||
|
||||
@@ -3,25 +3,39 @@
|
||||
// This file provides C wrappers for liblld.
|
||||
|
||||
#include <lld/Common/Driver.h>
|
||||
#include <llvm/Support/Parallel.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void configure() {
|
||||
#if _WIN64
|
||||
// This is a hack to work around a hang in the LLD linker on Windows, with
|
||||
// -DLLVM_ENABLE_THREADS=ON. It has a similar effect as the -threads=1
|
||||
// linker flag, but with support for the COFF linker.
|
||||
llvm::parallel::strategy = llvm::hardware_concurrency(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tinygo_link_elf(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_macho(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_mingw(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_wasm(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
+109
-19
@@ -1,27 +1,117 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/sigurn/crc16"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrfutil%2FUG%2Fnrfutil%2Fnrfutil_intro.html
|
||||
|
||||
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
|
||||
cmdLine := []string{"nrfutil", "pkg", "generate", "--hw-version", "52", "--sd-req", "0x0", "--debug-mode", "--application", infile, outfile}
|
||||
|
||||
if options.PrintCommands != nil {
|
||||
options.PrintCommands(cmdLine[0], cmdLine[1:]...)
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
|
||||
cmd.Stdout = io.Discard
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
|
||||
}
|
||||
return nil
|
||||
// Structure of the manifest.json file.
|
||||
type jsonManifest struct {
|
||||
Manifest struct {
|
||||
Application struct {
|
||||
BinaryFile string `json:"bin_file"`
|
||||
DataFile string `json:"dat_file"`
|
||||
InitPacketData nrfInitPacket `json:"init_packet_data"`
|
||||
} `json:"application"`
|
||||
DFUVersion float64 `json:"dfu_version"` // yes, this is a JSON number, not a string
|
||||
} `json:"manifest"`
|
||||
}
|
||||
|
||||
// Structure of the init packet.
|
||||
// Source:
|
||||
// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/lib/sdk11/components/libraries/bootloader_dfu/dfu_init.h#L47-L57
|
||||
type nrfInitPacket struct {
|
||||
ApplicationVersion uint32 `json:"application_version"`
|
||||
DeviceRevision uint16 `json:"device_revision"`
|
||||
DeviceType uint16 `json:"device_type"`
|
||||
FirmwareCRC16 uint16 `json:"firmware_crc16"`
|
||||
SoftDeviceRequired []uint16 `json:"softdevice_req"` // this is actually a variable length array
|
||||
}
|
||||
|
||||
// Create the init packet (the contents of application.dat).
|
||||
func (p nrfInitPacket) createInitPacket() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.LittleEndian, p.DeviceType) // uint16_t device_type;
|
||||
binary.Write(buf, binary.LittleEndian, p.DeviceRevision) // uint16_t device_rev;
|
||||
binary.Write(buf, binary.LittleEndian, p.ApplicationVersion) // uint32_t app_version;
|
||||
binary.Write(buf, binary.LittleEndian, uint16(len(p.SoftDeviceRequired))) // uint16_t softdevice_len;
|
||||
binary.Write(buf, binary.LittleEndian, p.SoftDeviceRequired) // uint16_t softdevice[1];
|
||||
binary.Write(buf, binary.LittleEndian, p.FirmwareCRC16)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// Make a Nordic DFU firmware image from an ELF file.
|
||||
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
|
||||
// Read ELF file as input and convert it to a binary image file.
|
||||
_, data, err := extractROM(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the zip file in memory.
|
||||
// It won't be very large anyway.
|
||||
buf := &bytes.Buffer{}
|
||||
w := zip.NewWriter(buf)
|
||||
|
||||
// Write the application binary to the zip file.
|
||||
binw, err := w.Create("application.bin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = binw.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the init packet.
|
||||
initPacket := nrfInitPacket{
|
||||
ApplicationVersion: 0xffff_ffff, // appears to be unused by the Adafruit bootloader
|
||||
DeviceRevision: 0xffff, // DFU_DEVICE_REVISION_EMPTY
|
||||
DeviceType: 0x0052, // ADAFRUIT_DEVICE_TYPE
|
||||
FirmwareCRC16: crc16.Checksum(data, crc16.MakeTable(crc16.CRC16_CCITT_FALSE)),
|
||||
SoftDeviceRequired: []uint16{0xfffe}, // DFU_SOFTDEVICE_ANY
|
||||
}
|
||||
|
||||
// Write the init packet to the zip file.
|
||||
datw, err := w.Create("application.dat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = datw.Write(initPacket.createInitPacket())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the JSON manifest.
|
||||
manifest := &jsonManifest{}
|
||||
manifest.Manifest.Application.BinaryFile = "application.bin"
|
||||
manifest.Manifest.Application.DataFile = "application.dat"
|
||||
manifest.Manifest.Application.InitPacketData = initPacket
|
||||
manifest.Manifest.DFUVersion = 0.5
|
||||
|
||||
// Write the JSON manifest to the file.
|
||||
jsonw, err := w.Create("manifest.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc := json.NewEncoder(jsonw)
|
||||
enc.SetIndent("", " ")
|
||||
err = enc.Encode(manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Finish the zip file.
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(outfile, buf.Bytes(), 0o666)
|
||||
}
|
||||
|
||||
+105
-27
@@ -75,6 +75,7 @@ func (ps *packageSize) RAM() uint64 {
|
||||
type addressLine struct {
|
||||
Address uint64
|
||||
Length uint64 // length of this chunk
|
||||
Align uint64 // (maximum) alignment of this line
|
||||
File string // file path as stored in DWARF
|
||||
IsVariable bool // true if this is a variable (or constant), false if it is code
|
||||
}
|
||||
@@ -86,6 +87,7 @@ type memorySection struct {
|
||||
Type memoryType
|
||||
Address uint64
|
||||
Size uint64
|
||||
Align uint64
|
||||
}
|
||||
|
||||
type memoryType int
|
||||
@@ -117,13 +119,13 @@ var (
|
||||
// alloc: heap allocations during init interpretation
|
||||
// pack: data created when storing a constant in an interface for example
|
||||
// string: buffer behind strings
|
||||
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|embedfsfiles|embedfsslice|embedslice|pack|string)(\.[0-9]+)?$`)
|
||||
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|pack|string)(\.[0-9]+)?$`)
|
||||
)
|
||||
|
||||
// readProgramSizeFromDWARF reads the source location for each line of code and
|
||||
// each variable in the program, as far as this is stored in the DWARF debug
|
||||
// information.
|
||||
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone bool) ([]addressLine, error) {
|
||||
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64, skipTombstone bool) ([]addressLine, error) {
|
||||
r := data.Reader()
|
||||
var lines []*dwarf.LineFile
|
||||
var addresses []addressLine
|
||||
@@ -195,6 +197,7 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
||||
line := addressLine{
|
||||
Address: prevLineEntry.Address + codeOffset,
|
||||
Length: lineEntry.Address - prevLineEntry.Address,
|
||||
Align: codeAlignment,
|
||||
File: prevLineEntry.File.Name,
|
||||
}
|
||||
if line.Length != 0 {
|
||||
@@ -219,20 +222,9 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
||||
// Try to parse the location. While this could in theory be a very
|
||||
// complex expression, usually it's just a DW_OP_addr opcode
|
||||
// followed by an address.
|
||||
locationCode := location.Val.([]uint8)
|
||||
if locationCode[0] != 3 { // DW_OP_addr
|
||||
continue
|
||||
}
|
||||
var addr uint64
|
||||
switch len(locationCode) {
|
||||
case 1 + 2:
|
||||
addr = uint64(binary.LittleEndian.Uint16(locationCode[1:]))
|
||||
case 1 + 4:
|
||||
addr = uint64(binary.LittleEndian.Uint32(locationCode[1:]))
|
||||
case 1 + 8:
|
||||
addr = binary.LittleEndian.Uint64(locationCode[1:])
|
||||
default:
|
||||
continue // unknown address
|
||||
addr, err := readDWARFConstant(r.AddressSize(), location.Val.([]uint8))
|
||||
if err != nil {
|
||||
continue // ignore the error, we don't know what to do with it
|
||||
}
|
||||
|
||||
// Parse the type of the global variable, which (importantly)
|
||||
@@ -243,9 +235,16 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read alignment, if it's stored as part of the debug information.
|
||||
var alignment uint64
|
||||
if attr := e.AttrField(dwarf.AttrAlignment); attr != nil {
|
||||
alignment = uint64(attr.Val.(int64))
|
||||
}
|
||||
|
||||
addresses = append(addresses, addressLine{
|
||||
Address: addr,
|
||||
Length: uint64(typ.Size()),
|
||||
Align: alignment,
|
||||
File: lines[file.Val.(int64)].Name,
|
||||
IsVariable: true,
|
||||
})
|
||||
@@ -256,6 +255,52 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
// Parse a DWARF constant. For addresses, this is usually a very simple
|
||||
// expression.
|
||||
func readDWARFConstant(addressSize int, bytecode []byte) (uint64, error) {
|
||||
var addr uint64
|
||||
for len(bytecode) != 0 {
|
||||
op := bytecode[0]
|
||||
bytecode = bytecode[1:]
|
||||
switch op {
|
||||
case 0x03: // DW_OP_addr
|
||||
switch addressSize {
|
||||
case 2:
|
||||
addr = uint64(binary.LittleEndian.Uint16(bytecode))
|
||||
case 4:
|
||||
addr = uint64(binary.LittleEndian.Uint32(bytecode))
|
||||
case 8:
|
||||
addr = binary.LittleEndian.Uint64(bytecode)
|
||||
default:
|
||||
panic("unexpected address size")
|
||||
}
|
||||
bytecode = bytecode[addressSize:]
|
||||
case 0x23: // DW_OP_plus_uconst
|
||||
offset, n := readULEB128(bytecode)
|
||||
addr += offset
|
||||
bytecode = bytecode[n:]
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown DWARF opcode: 0x%x", op)
|
||||
}
|
||||
}
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// Source: https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
|
||||
func readULEB128(buf []byte) (result uint64, n int) {
|
||||
var shift uint8
|
||||
for {
|
||||
b := buf[n]
|
||||
n++
|
||||
result |= uint64(b&0x7f) << shift
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
shift += 7
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Read a MachO object file and return a line table.
|
||||
// Also return an index from symbol name to start address in the line table.
|
||||
func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error) {
|
||||
@@ -277,7 +322,7 @@ func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
lines, err := readProgramSizeFromDWARF(dwarf, 0, false)
|
||||
lines, err := readProgramSizeFromDWARF(dwarf, 0, 0, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -334,10 +379,15 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
// Load the binary file, which could be in a number of file formats.
|
||||
var sections []memorySection
|
||||
if file, err := elf.NewFile(f); err == nil {
|
||||
var codeAlignment uint64
|
||||
switch file.Machine {
|
||||
case elf.EM_ARM:
|
||||
codeAlignment = 4 // usually 2, but can be 4
|
||||
}
|
||||
// Read DWARF information. The error is intentionally ignored.
|
||||
data, _ := file.DWARF()
|
||||
if data != nil {
|
||||
addresses, err = readProgramSizeFromDWARF(data, 0, true)
|
||||
addresses, err = readProgramSizeFromDWARF(data, 0, codeAlignment, true)
|
||||
if err != nil {
|
||||
// However, _do_ report an error here. Something must have gone
|
||||
// wrong while trying to parse DWARF data.
|
||||
@@ -371,7 +421,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
if section.Flags&elf.SHF_ALLOC == 0 {
|
||||
continue
|
||||
}
|
||||
if packageSymbolRegexp.MatchString(symbol.Name) {
|
||||
if packageSymbolRegexp.MatchString(symbol.Name) || symbol.Name == "__isr_vector" {
|
||||
addresses = append(addresses, addressLine{
|
||||
Address: symbol.Value,
|
||||
Length: symbol.Size,
|
||||
@@ -395,6 +445,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
Align: section.Addralign,
|
||||
Type: memoryStack,
|
||||
})
|
||||
} else {
|
||||
@@ -402,6 +453,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
Align: section.Addralign,
|
||||
Type: memoryBSS,
|
||||
})
|
||||
}
|
||||
@@ -410,6 +462,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
Align: section.Addralign,
|
||||
Type: memoryCode,
|
||||
})
|
||||
} else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_WRITE != 0 {
|
||||
@@ -417,6 +470,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
Align: section.Addralign,
|
||||
Type: memoryData,
|
||||
})
|
||||
} else if section.Type == elf.SHT_PROGBITS {
|
||||
@@ -424,6 +478,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
Align: section.Addralign,
|
||||
Type: memoryROData,
|
||||
})
|
||||
}
|
||||
@@ -450,6 +505,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: uint64(section.Size),
|
||||
Align: uint64(section.Align),
|
||||
Type: memoryCode,
|
||||
})
|
||||
} else if sectionType == 1 { // S_ZEROFILL
|
||||
@@ -457,6 +513,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: uint64(section.Size),
|
||||
Align: uint64(section.Align),
|
||||
Type: memoryBSS,
|
||||
})
|
||||
} else if segment.Maxprot&0b011 == 0b001 { // --r (read-only data)
|
||||
@@ -464,6 +521,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: uint64(section.Size),
|
||||
Align: uint64(section.Align),
|
||||
Type: memoryROData,
|
||||
})
|
||||
} else {
|
||||
@@ -471,6 +529,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: uint64(section.Size),
|
||||
Align: uint64(section.Align),
|
||||
Type: memoryData,
|
||||
})
|
||||
}
|
||||
@@ -554,7 +613,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
// Read DWARF information. The error is intentionally ignored.
|
||||
data, _ := file.DWARF()
|
||||
if data != nil {
|
||||
addresses, err = readProgramSizeFromDWARF(data, 0, true)
|
||||
addresses, err = readProgramSizeFromDWARF(data, 0, 0, true)
|
||||
if err != nil {
|
||||
// However, _do_ report an error here. Something must have gone
|
||||
// wrong while trying to parse DWARF data.
|
||||
@@ -626,7 +685,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
// Read DWARF information. The error is intentionally ignored.
|
||||
data, _ := file.DWARF()
|
||||
if data != nil {
|
||||
addresses, err = readProgramSizeFromDWARF(data, codeOffset, true)
|
||||
addresses, err = readProgramSizeFromDWARF(data, codeOffset, 0, true)
|
||||
if err != nil {
|
||||
// However, _do_ report an error here. Something must have gone
|
||||
// wrong while trying to parse DWARF data.
|
||||
@@ -786,10 +845,18 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
|
||||
if addr < line.Address {
|
||||
// There is a gap: there is a space between the current and the
|
||||
// previous line entry.
|
||||
addSize("(unknown)", line.Address-addr, false)
|
||||
if sizesDebug {
|
||||
fmt.Printf("%08x..%08x %5d: unknown (gap)\n", addr, line.Address, line.Address-addr)
|
||||
// Check whether this is caused by alignment requirements.
|
||||
addrAligned := (addr + line.Align - 1) &^ (line.Align - 1)
|
||||
if line.Align > 1 && addrAligned >= line.Address {
|
||||
// It is, assume that's what causes the gap.
|
||||
addSize("(padding)", line.Address-addr, true)
|
||||
} else {
|
||||
addSize("(unknown)", line.Address-addr, false)
|
||||
if sizesDebug {
|
||||
fmt.Printf("%08x..%08x %5d: unknown (gap), alignment=%d\n", addr, line.Address, line.Address-addr, line.Align)
|
||||
}
|
||||
}
|
||||
addr = line.Address
|
||||
}
|
||||
if addr > line.Address+line.Length {
|
||||
// The current line is already covered by a previous line entry.
|
||||
@@ -811,9 +878,16 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
|
||||
}
|
||||
if addr < sectionEnd {
|
||||
// There is a gap at the end of the section.
|
||||
addSize("(unknown)", sectionEnd-addr, false)
|
||||
if sizesDebug {
|
||||
fmt.Printf("%08x..%08x %5d: unknown (end)\n", addr, sectionEnd, sectionEnd-addr)
|
||||
addrAligned := (addr + section.Align - 1) &^ (section.Align - 1)
|
||||
if section.Align > 1 && addrAligned >= sectionEnd {
|
||||
// The gap is caused by the section alignment.
|
||||
// For example, if a .rodata section ends with a non-aligned string.
|
||||
addSize("(padding)", sectionEnd-addr, true)
|
||||
} else {
|
||||
addSize("(unknown)", sectionEnd-addr, false)
|
||||
if sizesDebug {
|
||||
fmt.Printf("%08x..%08x %5d: unknown (end), alignment=%d\n", addr, sectionEnd, sectionEnd-addr, section.Align)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,9 +903,13 @@ func findPackagePath(path string, packagePathMap map[string]string) string {
|
||||
// package, with a "C" prefix. For example: "C compiler-rt" for the
|
||||
// compiler runtime library from LLVM.
|
||||
packagePath = "C " + strings.Split(strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")), string(os.PathSeparator))[1]
|
||||
} else if strings.HasPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project")) {
|
||||
packagePath = "C compiler-rt"
|
||||
} else if packageSymbolRegexp.MatchString(path) {
|
||||
// Parse symbol names like main$alloc or runtime$string.
|
||||
packagePath = path[:strings.LastIndex(path, "$")]
|
||||
} else if path == "__isr_vector" {
|
||||
packagePath = "C interrupt vector"
|
||||
} else if path == "<Go type>" {
|
||||
packagePath = "Go types"
|
||||
} else if path == "<Go interface assert>" {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
var sema = make(chan struct{}, runtime.NumCPU())
|
||||
|
||||
type sizeTest struct {
|
||||
target string
|
||||
path string
|
||||
codeSize uint64
|
||||
rodataSize uint64
|
||||
dataSize uint64
|
||||
bssSize uint64
|
||||
}
|
||||
|
||||
// Test whether code and data size is as expected for the given targets.
|
||||
// This tests both the logic of loadProgramSize and checks that code size
|
||||
// doesn't change unintentionally.
|
||||
//
|
||||
// If you find that code or data size is reduced, then great! You can reduce the
|
||||
// number in this test.
|
||||
// If you find that the code or data size is increased, take a look as to why
|
||||
// this is. It could be due to an update (LLVM version, Go version, etc) which
|
||||
// is fine, but it could also mean that a recent change introduced this size
|
||||
// increase. If so, please consider whether this new feature is indeed worth the
|
||||
// size increase for all users.
|
||||
func TestBinarySize(t *testing.T) {
|
||||
if runtime.GOOS == "linux" && !hasBuiltinTools {
|
||||
// Debian LLVM packages are modified a bit and tend to produce
|
||||
// different machine code. Ideally we'd fix this (with some attributes
|
||||
// or something?), but for now skip it.
|
||||
t.Skip("Skip: using external LLVM version so binary size might differ")
|
||||
}
|
||||
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4612, 280, 0, 2252},
|
||||
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6159, 1485, 116, 6816},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
// output varies by binaryen version.
|
||||
}
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.target+"/"+tc.path, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Build the binary.
|
||||
options := compileopts.Options{
|
||||
Target: tc.target,
|
||||
Opt: "z",
|
||||
Semaphore: sema,
|
||||
InterpTimeout: 60 * time.Second,
|
||||
Debug: true,
|
||||
VerifyIR: true,
|
||||
}
|
||||
target, err := compileopts.LoadTarget(&options)
|
||||
if err != nil {
|
||||
t.Fatal("could not load target:", err)
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: &options,
|
||||
Target: target,
|
||||
}
|
||||
result, err := Build(tc.path, "", t.TempDir(), config)
|
||||
if err != nil {
|
||||
t.Fatal("could not build:", err)
|
||||
}
|
||||
|
||||
// Check whether the size of the binary matches the expected size.
|
||||
sizes, err := loadProgramSize(result.Executable, nil)
|
||||
if err != nil {
|
||||
t.Fatal("could not read program size:", err)
|
||||
}
|
||||
if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize {
|
||||
t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path)
|
||||
t.Errorf(" code rodata data bss")
|
||||
t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize)
|
||||
t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,7 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`--export=([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
|
||||
@@ -108,6 +108,7 @@ var goodLinkerFlags = [][]string{
|
||||
{"-Fbar"},
|
||||
{"-lbar"},
|
||||
{"-Lbar"},
|
||||
{"--export=my_symbol"},
|
||||
{"-fpic"},
|
||||
{"-fno-pic"},
|
||||
{"-fPIC"},
|
||||
|
||||
+11
-27
@@ -75,8 +75,7 @@ func (c *Config) GOARM() string {
|
||||
|
||||
// BuildTags returns the complete list of build tags used during this build.
|
||||
func (c *Config) BuildTags() []string {
|
||||
targetTags := filterTags(c.Target.BuildTags, c.Options.Tags)
|
||||
tags := append(targetTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||
}
|
||||
@@ -541,29 +540,14 @@ func (c *Config) Emulator(format, binary string) ([]string, error) {
|
||||
|
||||
type TestConfig struct {
|
||||
CompileTestBinary bool
|
||||
// TODO: Filter the test functions to run, include verbose flag, etc
|
||||
}
|
||||
|
||||
// filterTags removes predefined build tags for a target if a conflicting option
|
||||
// is provided by the user.
|
||||
func filterTags(targetTags []string, userTags []string) []string {
|
||||
var filtered []string
|
||||
for _, t := range targetTags {
|
||||
switch {
|
||||
case strings.HasPrefix(t, "runtime_memhash_"):
|
||||
overridden := false
|
||||
for _, ut := range userTags {
|
||||
if strings.HasPrefix(ut, "runtime_memhash_") {
|
||||
overridden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !overridden {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
default:
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
CompileOnly bool
|
||||
Verbose bool
|
||||
Short bool
|
||||
RunRegexp string
|
||||
SkipRegexp string
|
||||
Count *int
|
||||
BenchRegexp string
|
||||
BenchTime string
|
||||
BenchMem bool
|
||||
Shuffle string
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package compileopts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildTags(t *testing.T) {
|
||||
tests := []struct {
|
||||
targetTags []string
|
||||
userTags []string
|
||||
result []string
|
||||
}{
|
||||
{
|
||||
targetTags: []string{},
|
||||
userTags: []string{},
|
||||
result: []string{
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear"},
|
||||
userTags: []string{},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear"},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"runtime_memhash_leveldb",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat", "runtime_memhash_leveldb"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
"runtime_memhash_leveldb",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat", "runtime_memhash_sip"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
"runtime_memhash_sip",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tt := tc
|
||||
t.Run(fmt.Sprintf("%s+%s", strings.Join(tt.targetTags, ","), strings.Join(tt.userTags, ",")), func(t *testing.T) {
|
||||
c := &Config{
|
||||
Target: &TargetSpec{
|
||||
BuildTags: tt.targetTags,
|
||||
},
|
||||
Options: &Options{
|
||||
Tags: tt.userTags,
|
||||
},
|
||||
}
|
||||
|
||||
res := c.BuildTags()
|
||||
|
||||
if len(res) != len(tt.result) {
|
||||
t.Errorf("expected %d tags, got %d", len(tt.result), len(res))
|
||||
}
|
||||
|
||||
for i, tag := range tt.result {
|
||||
if tag != res[i] {
|
||||
t.Errorf("tag %d: expected %s, got %s", i, tt.result[i], tag)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ type Options struct {
|
||||
PrintIR bool
|
||||
DumpSSA bool
|
||||
VerifyIR bool
|
||||
SkipDWARF bool
|
||||
PrintCommands func(cmd string, args ...string) `json:"-"`
|
||||
Semaphore chan struct{} `json:"-"` // -p flag controls cap
|
||||
Debug bool
|
||||
|
||||
@@ -50,7 +50,7 @@ type TargetSpec struct {
|
||||
PortReset string `json:"flash-1200-bps-reset"`
|
||||
SerialPort []string `json:"serial-port"` // serial port IDs in the form "vid:pid"
|
||||
FlashMethod string `json:"flash-method"`
|
||||
FlashVolume string `json:"msd-volume-name"`
|
||||
FlashVolume []string `json:"msd-volume-name"`
|
||||
FlashFilename string `json:"msd-firmware-name"`
|
||||
UF2FamilyID string `json:"uf2-family-id"`
|
||||
BinaryFormat string `json:"binary-format"`
|
||||
|
||||
+10
-10
@@ -13,8 +13,8 @@ import (
|
||||
func (b *builder) createAtomicOp(name string) llvm.Value {
|
||||
switch name {
|
||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||
ptr := b.getValue(b.fn.Params[0])
|
||||
val := b.getValue(b.fn.Params[1])
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
if strings.HasPrefix(b.Triple, "avr") {
|
||||
// AtomicRMW does not work on AVR as intended:
|
||||
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
|
||||
@@ -33,8 +33,8 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
||||
// Return the new value, not the original value returned by atomicrmw.
|
||||
return b.CreateAdd(oldVal, val, "")
|
||||
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
||||
ptr := b.getValue(b.fn.Params[0])
|
||||
val := b.getValue(b.fn.Params[1])
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
|
||||
if isPointer {
|
||||
// atomicrmw only supports integers, so cast to an integer.
|
||||
@@ -48,21 +48,21 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
||||
}
|
||||
return oldVal
|
||||
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
||||
ptr := b.getValue(b.fn.Params[0])
|
||||
old := b.getValue(b.fn.Params[1])
|
||||
newVal := b.getValue(b.fn.Params[2])
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
old := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
newVal := b.getValue(b.fn.Params[2], getPos(b.fn))
|
||||
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
swapped := b.CreateExtractValue(tuple, 1, "")
|
||||
return swapped
|
||||
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
|
||||
ptr := b.getValue(b.fn.Params[0])
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.CreateLoad(b.getLLVMType(b.fn.Signature.Results().At(0).Type()), ptr, "")
|
||||
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||
return val
|
||||
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
||||
ptr := b.getValue(b.fn.Params[0])
|
||||
val := b.getValue(b.fn.Params[1])
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
if strings.HasPrefix(b.Triple, "avr") {
|
||||
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
|
||||
vType := val.Type()
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ func extractSubfield(t types.Type, field int) types.Type {
|
||||
}
|
||||
}
|
||||
|
||||
// flattenAggregateTypeOffset returns the offsets from the start of an object of
|
||||
// flattenAggregateTypeOffsets returns the offsets from the start of an object of
|
||||
// type t if this object were flattened like in flattenAggregate. Used together
|
||||
// with flattenAggregate to know the start indices of each value in the
|
||||
// non-flattened object.
|
||||
|
||||
+8
-8
@@ -14,7 +14,7 @@ import (
|
||||
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
|
||||
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().Underlying().(*types.Chan).Elem()))
|
||||
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
|
||||
bufSize := b.getValue(expr.Size)
|
||||
bufSize := b.getValue(expr.Size, getPos(expr))
|
||||
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
|
||||
if bufSize.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
|
||||
bufSize = b.CreateZExt(bufSize, b.uintptrType, "")
|
||||
@@ -27,8 +27,8 @@ func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
|
||||
// createChanSend emits a pseudo chan send operation. It is lowered to the
|
||||
// actual channel send operation during goroutine lowering.
|
||||
func (b *builder) createChanSend(instr *ssa.Send) {
|
||||
ch := b.getValue(instr.Chan)
|
||||
chanValue := b.getValue(instr.X)
|
||||
ch := b.getValue(instr.Chan, getPos(instr))
|
||||
chanValue := b.getValue(instr.X, getPos(instr))
|
||||
|
||||
// store value-to-send
|
||||
valueType := b.getLLVMType(instr.X.Type())
|
||||
@@ -62,7 +62,7 @@ func (b *builder) createChanSend(instr *ssa.Send) {
|
||||
// actual channel receive operation during goroutine lowering.
|
||||
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
||||
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Chan).Elem())
|
||||
ch := b.getValue(unop.X)
|
||||
ch := b.getValue(unop.X, getPos(unop))
|
||||
|
||||
// Allocate memory to receive into.
|
||||
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
|
||||
@@ -140,7 +140,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
||||
var selectStates []llvm.Value
|
||||
chanSelectStateType := b.getLLVMRuntimeType("chanSelectState")
|
||||
for _, state := range expr.States {
|
||||
ch := b.getValue(state.Chan)
|
||||
ch := b.getValue(state.Chan, state.Pos)
|
||||
selectState := llvm.ConstNull(chanSelectStateType)
|
||||
selectState = b.CreateInsertValue(selectState, ch, 0, "")
|
||||
switch state.Dir {
|
||||
@@ -156,7 +156,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
||||
case types.SendOnly:
|
||||
// Store this value in an alloca and put a pointer to this alloca
|
||||
// in the send state.
|
||||
sendValue := b.getValue(state.Send)
|
||||
sendValue := b.getValue(state.Send, state.Pos)
|
||||
alloca := llvmutil.CreateEntryBlockAlloca(b.Builder, sendValue.Type(), "select.send.value")
|
||||
b.CreateStore(sendValue, alloca)
|
||||
ptr := b.CreateBitCast(alloca, b.i8ptrType, "")
|
||||
@@ -247,7 +247,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
||||
func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
|
||||
if expr.Index == 0 {
|
||||
// index
|
||||
value := b.getValue(expr.Tuple)
|
||||
value := b.getValue(expr.Tuple, getPos(expr))
|
||||
index := b.CreateExtractValue(value, expr.Index, "")
|
||||
if index.Type().IntTypeWidth() < b.intType.IntTypeWidth() {
|
||||
index = b.CreateSExt(index, b.intType, "")
|
||||
@@ -255,7 +255,7 @@ func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
|
||||
return index
|
||||
} else if expr.Index == 1 {
|
||||
// comma-ok
|
||||
value := b.getValue(expr.Tuple)
|
||||
value := b.getValue(expr.Tuple, getPos(expr))
|
||||
return b.CreateExtractValue(value, expr.Index, "")
|
||||
} else {
|
||||
// Select statements are (index, ok, ...) where ... is a number of
|
||||
|
||||
+157
-98
@@ -71,6 +71,7 @@ type compilerContext struct {
|
||||
difiles map[string]llvm.Metadata
|
||||
ditypes map[types.Type]llvm.Metadata
|
||||
llvmTypes typeutil.Map
|
||||
interfaceTypes typeutil.Map
|
||||
machine llvm.TargetMachine
|
||||
targetData llvm.TargetData
|
||||
intType llvm.Type
|
||||
@@ -81,6 +82,7 @@ type compilerContext struct {
|
||||
uintptrType llvm.Type
|
||||
program *ssa.Program
|
||||
diagnostics []error
|
||||
functionInfos map[*ssa.Function]functionInfo
|
||||
astComments map[string]*ast.CommentGroup
|
||||
embedGlobals map[string][]*loader.EmbedFile
|
||||
pkg *types.Package
|
||||
@@ -92,13 +94,14 @@ type compilerContext struct {
|
||||
// importantly with a newly created LLVM context and module.
|
||||
func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *Config, dumpSSA bool) *compilerContext {
|
||||
c := &compilerContext{
|
||||
Config: config,
|
||||
DumpSSA: dumpSSA,
|
||||
difiles: make(map[string]llvm.Metadata),
|
||||
ditypes: make(map[types.Type]llvm.Metadata),
|
||||
machine: machine,
|
||||
targetData: machine.CreateTargetData(),
|
||||
astComments: map[string]*ast.CommentGroup{},
|
||||
Config: config,
|
||||
DumpSSA: dumpSSA,
|
||||
difiles: make(map[string]llvm.Metadata),
|
||||
ditypes: make(map[types.Type]llvm.Metadata),
|
||||
machine: machine,
|
||||
targetData: machine.CreateTargetData(),
|
||||
functionInfos: map[*ssa.Function]functionInfo{},
|
||||
astComments: map[string]*ast.CommentGroup{},
|
||||
}
|
||||
|
||||
c.ctx = llvm.NewContext()
|
||||
@@ -166,6 +169,8 @@ type builder struct {
|
||||
deferExprFuncs map[ssa.Value]int
|
||||
selectRecvBuf map[*ssa.Select]llvm.Value
|
||||
deferBuiltinFuncs map[ssa.Value]deferBuiltin
|
||||
runDefersBlock []llvm.BasicBlock
|
||||
afterDefersBlock []llvm.BasicBlock
|
||||
}
|
||||
|
||||
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
|
||||
@@ -569,10 +574,19 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
||||
case *types.Map:
|
||||
return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type()))
|
||||
case *types.Named:
|
||||
return c.dibuilder.CreateTypedef(llvm.DITypedef{
|
||||
// Placeholder metadata node, to be replaced afterwards.
|
||||
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
|
||||
Tag: dwarf.TagTypedef,
|
||||
SizeInBits: sizeInBytes * 8,
|
||||
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
|
||||
})
|
||||
c.ditypes[typ] = temporaryMDNode
|
||||
md := c.dibuilder.CreateTypedef(llvm.DITypedef{
|
||||
Type: c.getDIType(typ.Underlying()),
|
||||
Name: typ.String(),
|
||||
})
|
||||
temporaryMDNode.ReplaceAllUsesWith(md)
|
||||
return md
|
||||
case *types.Pointer:
|
||||
return c.dibuilder.CreatePointerType(llvm.DIPointerType{
|
||||
Pointee: c.getDIType(typ.Elem()),
|
||||
@@ -634,13 +648,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
||||
},
|
||||
})
|
||||
case *types.Struct:
|
||||
// Placeholder metadata node, to be replaced afterwards.
|
||||
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
|
||||
Tag: dwarf.TagStructType,
|
||||
SizeInBits: sizeInBytes * 8,
|
||||
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
|
||||
})
|
||||
c.ditypes[typ] = temporaryMDNode
|
||||
elements := make([]llvm.Metadata, typ.NumFields())
|
||||
for i := range elements {
|
||||
field := typ.Field(i)
|
||||
@@ -659,7 +666,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
||||
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
|
||||
Elements: elements,
|
||||
})
|
||||
temporaryMDNode.ReplaceAllUsesWith(md)
|
||||
return md
|
||||
case *types.TypeParam:
|
||||
return c.getDIType(typ.Underlying())
|
||||
@@ -843,6 +849,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
b.defineMathOp()
|
||||
continue
|
||||
}
|
||||
if ok := b.defineMathBitsIntrinsic(); ok {
|
||||
// Like a math intrinsic, the body of this function was replaced
|
||||
// with a LLVM intrinsic.
|
||||
continue
|
||||
}
|
||||
if member.Blocks == nil {
|
||||
// Try to define this as an intrinsic function.
|
||||
b.defineIntrinsicFunction()
|
||||
@@ -869,14 +880,14 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
if fn == nil {
|
||||
continue // probably a generic method
|
||||
}
|
||||
if fn.Blocks == nil {
|
||||
continue // external function
|
||||
}
|
||||
if member.Type().String() != member.String() {
|
||||
// This is a member on a type alias. Do not build such a
|
||||
// function.
|
||||
continue
|
||||
}
|
||||
if fn.Blocks == nil {
|
||||
continue // external function
|
||||
}
|
||||
if fn.Synthetic != "" && fn.Synthetic != "package initializer" {
|
||||
// This function is a kind of wrapper function (created by
|
||||
// the ssa package, not appearing in the source code) that
|
||||
@@ -970,6 +981,19 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
||||
global.SetInitializer(sliceObj)
|
||||
global.SetVisibility(llvm.HiddenVisibility)
|
||||
|
||||
if c.Debug {
|
||||
// Add debug info to the slice backing array.
|
||||
position := c.program.Fset.Position(member.Pos())
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
|
||||
File: c.getDIFile(position.Filename),
|
||||
Line: position.Line,
|
||||
Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(file.Data)))),
|
||||
LocalToUnit: true,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
})
|
||||
bufferGlobal.AddMetadata(0, diglobal)
|
||||
}
|
||||
|
||||
case *types.Struct:
|
||||
// Assume this is an embed.FS struct:
|
||||
// https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/embed/embed.go;l=148
|
||||
@@ -1010,11 +1034,12 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
||||
})
|
||||
|
||||
// Make the backing array for the []files slice. This is a LLVM global.
|
||||
embedFileStructType := c.getLLVMType(typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem())
|
||||
embedFileStructType := typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem()
|
||||
llvmEmbedFileStructType := c.getLLVMType(embedFileStructType)
|
||||
var fileStructs []llvm.Value
|
||||
for _, file := range allFiles {
|
||||
fileStruct := llvm.ConstNull(embedFileStructType)
|
||||
name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]))
|
||||
fileStruct := llvm.ConstNull(llvmEmbedFileStructType)
|
||||
name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]), getPos(member))
|
||||
fileStruct = c.builder.CreateInsertValue(fileStruct, name, 0, "") // "name" field
|
||||
if file.Hash != "" {
|
||||
data := c.getEmbedFileString(file)
|
||||
@@ -1022,13 +1047,25 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
||||
}
|
||||
fileStructs = append(fileStructs, fileStruct)
|
||||
}
|
||||
sliceDataInitializer := llvm.ConstArray(embedFileStructType, fileStructs)
|
||||
sliceDataInitializer := llvm.ConstArray(llvmEmbedFileStructType, fileStructs)
|
||||
sliceDataGlobal := llvm.AddGlobal(c.mod, sliceDataInitializer.Type(), c.pkg.Path()+"$embedfsfiles")
|
||||
sliceDataGlobal.SetInitializer(sliceDataInitializer)
|
||||
sliceDataGlobal.SetLinkage(llvm.InternalLinkage)
|
||||
sliceDataGlobal.SetGlobalConstant(true)
|
||||
sliceDataGlobal.SetUnnamedAddr(true)
|
||||
sliceDataGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceDataInitializer.Type()))
|
||||
if c.Debug {
|
||||
// Add debug information for code size attribution (among others).
|
||||
position := c.program.Fset.Position(member.Pos())
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
|
||||
File: c.getDIFile(position.Filename),
|
||||
Line: position.Line,
|
||||
Type: c.getDIType(types.NewArray(embedFileStructType, int64(len(allFiles)))),
|
||||
LocalToUnit: true,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
})
|
||||
sliceDataGlobal.AddMetadata(0, diglobal)
|
||||
}
|
||||
|
||||
// Create the slice object itself.
|
||||
// Because embed.FS refers to it as *[]embed.file instead of a plain
|
||||
@@ -1045,6 +1082,17 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
||||
sliceGlobal.SetGlobalConstant(true)
|
||||
sliceGlobal.SetUnnamedAddr(true)
|
||||
sliceGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceInitializer.Type()))
|
||||
if c.Debug {
|
||||
position := c.program.Fset.Position(member.Pos())
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
|
||||
File: c.getDIFile(position.Filename),
|
||||
Line: position.Line,
|
||||
Type: c.getDIType(types.NewSlice(embedFileStructType)),
|
||||
LocalToUnit: true,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
})
|
||||
sliceGlobal.AddMetadata(0, diglobal)
|
||||
}
|
||||
|
||||
// Define the embed.FS struct. It has only one field: the files (as a
|
||||
// *[]embed.file).
|
||||
@@ -1284,7 +1332,7 @@ func (b *builder) createFunction() {
|
||||
}
|
||||
dbgVar := b.getLocalVariable(variable)
|
||||
pos := b.program.Fset.Position(instr.Pos())
|
||||
b.dibuilder.InsertValueAtEnd(b.getValue(instr.X), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
|
||||
b.dibuilder.InsertValueAtEnd(b.getValue(instr.X, getPos(instr)), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
|
||||
Line: uint(pos.Line),
|
||||
Col: uint(pos.Column),
|
||||
Scope: b.difunc,
|
||||
@@ -1305,6 +1353,15 @@ func (b *builder) createFunction() {
|
||||
}
|
||||
}
|
||||
|
||||
// The rundefers instruction needs to be created after all defer
|
||||
// instructions have been created. Otherwise it won't handle all defer
|
||||
// cases.
|
||||
for i, bb := range b.runDefersBlock {
|
||||
b.SetInsertPointAtEnd(bb)
|
||||
b.createRunDefers()
|
||||
b.CreateBr(b.afterDefersBlock[i])
|
||||
}
|
||||
|
||||
if b.hasDeferFrame() {
|
||||
// Create the landing pad block, where execution continues after a
|
||||
// panic.
|
||||
@@ -1315,7 +1372,7 @@ func (b *builder) createFunction() {
|
||||
for _, phi := range b.phis {
|
||||
block := phi.ssa.Block()
|
||||
for i, edge := range phi.ssa.Edges {
|
||||
llvmVal := b.getValue(edge)
|
||||
llvmVal := b.getValue(edge, getPos(phi.ssa))
|
||||
llvmBlock := b.blockExits[block.Preds[i]]
|
||||
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
||||
}
|
||||
@@ -1423,7 +1480,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
// Start a new goroutine.
|
||||
b.createGo(instr)
|
||||
case *ssa.If:
|
||||
cond := b.getValue(instr.Cond)
|
||||
cond := b.getValue(instr.Cond, getPos(instr))
|
||||
block := instr.Block()
|
||||
blockThen := b.blockEntries[block.Succs[0]]
|
||||
blockElse := b.blockEntries[block.Succs[1]]
|
||||
@@ -1432,13 +1489,13 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
blockJump := b.blockEntries[instr.Block().Succs[0]]
|
||||
b.CreateBr(blockJump)
|
||||
case *ssa.MapUpdate:
|
||||
m := b.getValue(instr.Map)
|
||||
key := b.getValue(instr.Key)
|
||||
value := b.getValue(instr.Value)
|
||||
m := b.getValue(instr.Map, getPos(instr))
|
||||
key := b.getValue(instr.Key, getPos(instr))
|
||||
value := b.getValue(instr.Value, getPos(instr))
|
||||
mapType := instr.Map.Type().Underlying().(*types.Map)
|
||||
b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
|
||||
case *ssa.Panic:
|
||||
value := b.getValue(instr.X)
|
||||
value := b.getValue(instr.X, getPos(instr))
|
||||
b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
|
||||
b.CreateUnreachable()
|
||||
case *ssa.Return:
|
||||
@@ -1448,23 +1505,30 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
if len(instr.Results) == 0 {
|
||||
b.CreateRetVoid()
|
||||
} else if len(instr.Results) == 1 {
|
||||
b.CreateRet(b.getValue(instr.Results[0]))
|
||||
b.CreateRet(b.getValue(instr.Results[0], getPos(instr)))
|
||||
} else {
|
||||
// Multiple return values. Put them all in a struct.
|
||||
retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType())
|
||||
for i, result := range instr.Results {
|
||||
val := b.getValue(result)
|
||||
val := b.getValue(result, getPos(instr))
|
||||
retVal = b.CreateInsertValue(retVal, val, i, "")
|
||||
}
|
||||
b.CreateRet(retVal)
|
||||
}
|
||||
case *ssa.RunDefers:
|
||||
b.createRunDefers()
|
||||
// Note where we're going to put the rundefers block
|
||||
run := b.insertBasicBlock("rundefers.block")
|
||||
b.CreateBr(run)
|
||||
b.runDefersBlock = append(b.runDefersBlock, run)
|
||||
|
||||
after := b.insertBasicBlock("rundefers.after")
|
||||
b.SetInsertPointAtEnd(after)
|
||||
b.afterDefersBlock = append(b.afterDefersBlock, after)
|
||||
case *ssa.Send:
|
||||
b.createChanSend(instr)
|
||||
case *ssa.Store:
|
||||
llvmAddr := b.getValue(instr.Addr)
|
||||
llvmVal := b.getValue(instr.Val)
|
||||
llvmAddr := b.getValue(instr.Addr, getPos(instr))
|
||||
llvmVal := b.getValue(instr.Val, getPos(instr))
|
||||
b.createNilCheck(instr.Addr, llvmAddr, "store")
|
||||
if b.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
|
||||
// nothing to store
|
||||
@@ -1723,7 +1787,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Args {
|
||||
params = append(params, b.getValue(param))
|
||||
params = append(params, b.getValue(param, getPos(instr)))
|
||||
}
|
||||
|
||||
// Try to call the function directly for trivially static calls.
|
||||
@@ -1740,9 +1804,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
|
||||
return b.createInlineAsmFull(instr)
|
||||
case strings.HasPrefix(name, "device/arm.SVCall"):
|
||||
return b.emitSVCall(instr.Args)
|
||||
return b.emitSVCall(instr.Args, getPos(instr))
|
||||
case strings.HasPrefix(name, "device/arm64.SVCall"):
|
||||
return b.emitSV64Call(instr.Args)
|
||||
return b.emitSV64Call(instr.Args, getPos(instr))
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
|
||||
@@ -1779,7 +1843,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case *ssa.MakeClosure:
|
||||
// A call on a func value, but the callee is trivial to find. For
|
||||
// example: immediately applied functions.
|
||||
funcValue := b.getValue(value)
|
||||
funcValue := b.getValue(value, getPos(value))
|
||||
context = b.extractFuncContext(funcValue)
|
||||
default:
|
||||
panic("StaticCallee returned an unexpected value")
|
||||
@@ -1794,7 +1858,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return b.createBuiltin(argTypes, params, call.Name(), instr.Pos())
|
||||
} else if instr.IsInvoke() {
|
||||
// Interface method call (aka invoke call).
|
||||
itf := b.getValue(instr.Value) // interface value (runtime._interface)
|
||||
itf := b.getValue(instr.Value, getPos(instr)) // interface value (runtime._interface)
|
||||
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
||||
value := b.CreateExtractValue(itf, 1, "invoke.func.value") // receiver
|
||||
// Prefix the params with receiver value and suffix with typecode.
|
||||
@@ -1805,7 +1869,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
context = llvm.Undef(b.i8ptrType)
|
||||
} else {
|
||||
// Function pointer.
|
||||
value := b.getValue(instr.Value)
|
||||
value := b.getValue(instr.Value, getPos(instr))
|
||||
// This is a func value, which cannot be called directly. We have to
|
||||
// extract the function pointer and context first from the func value.
|
||||
calleeType, callee, context = b.decodeFuncValue(value, instr.Value.Type().Underlying().(*types.Signature))
|
||||
@@ -1823,10 +1887,18 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
|
||||
// getValue returns the LLVM value of a constant, function value, global, or
|
||||
// already processed SSA expression.
|
||||
func (b *builder) getValue(expr ssa.Value) llvm.Value {
|
||||
func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
|
||||
switch expr := expr.(type) {
|
||||
case *ssa.Const:
|
||||
return b.createConst(expr)
|
||||
if pos == token.NoPos {
|
||||
// If the position isn't known, at least try to find in which file
|
||||
// it is defined.
|
||||
file := b.program.Fset.File(b.fn.Pos())
|
||||
if file != nil {
|
||||
pos = file.Pos(0)
|
||||
}
|
||||
}
|
||||
return b.createConst(expr, pos)
|
||||
case *ssa.Function:
|
||||
if b.getFunctionInfo(expr).exported {
|
||||
b.addError(expr.Pos(), "cannot use an exported function as value: "+expr.String())
|
||||
@@ -1911,8 +1983,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
return buf, nil
|
||||
}
|
||||
case *ssa.BinOp:
|
||||
x := b.getValue(expr.X)
|
||||
y := b.getValue(expr.Y)
|
||||
x := b.getValue(expr.X, getPos(expr))
|
||||
y := b.getValue(expr.Y, getPos(expr))
|
||||
return b.createBinOp(expr.Op, expr.X.Type(), expr.Y.Type(), x, y, expr.Pos())
|
||||
case *ssa.Call:
|
||||
return b.createFunctionCall(expr.Common())
|
||||
@@ -1923,12 +1995,12 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
// This is different from how the official Go compiler works, because of
|
||||
// heap allocation and because it's easier to implement, see:
|
||||
// https://research.swtch.com/interfaces
|
||||
return b.getValue(expr.X), nil
|
||||
return b.getValue(expr.X, getPos(expr)), nil
|
||||
case *ssa.ChangeType:
|
||||
// This instruction changes the type, but the underlying value remains
|
||||
// the same. This is often a no-op, but sometimes we have to change the
|
||||
// LLVM type as well.
|
||||
x := b.getValue(expr.X)
|
||||
x := b.getValue(expr.X, getPos(expr))
|
||||
llvmType := b.getLLVMType(expr.Type())
|
||||
if x.Type() == llvmType {
|
||||
// Different Go type but same LLVM type (for example, named int).
|
||||
@@ -1957,20 +2029,20 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
case *ssa.Const:
|
||||
panic("const is not an expression")
|
||||
case *ssa.Convert:
|
||||
x := b.getValue(expr.X)
|
||||
x := b.getValue(expr.X, getPos(expr))
|
||||
return b.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
|
||||
case *ssa.Extract:
|
||||
if _, ok := expr.Tuple.(*ssa.Select); ok {
|
||||
return b.getChanSelectResult(expr), nil
|
||||
}
|
||||
value := b.getValue(expr.Tuple)
|
||||
value := b.getValue(expr.Tuple, getPos(expr))
|
||||
return b.CreateExtractValue(value, expr.Index, ""), nil
|
||||
case *ssa.Field:
|
||||
value := b.getValue(expr.X)
|
||||
value := b.getValue(expr.X, getPos(expr))
|
||||
result := b.CreateExtractValue(value, expr.Field, "")
|
||||
return result, nil
|
||||
case *ssa.FieldAddr:
|
||||
val := b.getValue(expr.X)
|
||||
val := b.getValue(expr.X, getPos(expr))
|
||||
// Check for nil pointer before calculating the address, from the spec:
|
||||
// > For an operand x of type T, the address operation &x generates a
|
||||
// > pointer of type *T to x. [...] If the evaluation of x would cause a
|
||||
@@ -1988,8 +2060,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
case *ssa.Global:
|
||||
panic("global is not an expression")
|
||||
case *ssa.Index:
|
||||
collection := b.getValue(expr.X)
|
||||
index := b.getValue(expr.Index)
|
||||
collection := b.getValue(expr.X, getPos(expr))
|
||||
index := b.getValue(expr.Index, getPos(expr))
|
||||
|
||||
switch xType := expr.X.Type().Underlying().(type) {
|
||||
case *types.Basic: // extract byte from string
|
||||
@@ -2038,8 +2110,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
panic("unknown *ssa.Index type")
|
||||
}
|
||||
case *ssa.IndexAddr:
|
||||
val := b.getValue(expr.X)
|
||||
index := b.getValue(expr.Index)
|
||||
val := b.getValue(expr.X, getPos(expr))
|
||||
index := b.getValue(expr.Index, getPos(expr))
|
||||
|
||||
// Get buffer pointer and length
|
||||
var bufptr, buflen llvm.Value
|
||||
@@ -2090,8 +2162,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
case *ssa.Lookup: // map lookup
|
||||
value := b.getValue(expr.X)
|
||||
index := b.getValue(expr.Index)
|
||||
value := b.getValue(expr.X, getPos(expr))
|
||||
index := b.getValue(expr.Index, getPos(expr))
|
||||
valueType := expr.Type()
|
||||
if expr.CommaOk {
|
||||
valueType = valueType.(*types.Tuple).At(0).Type()
|
||||
@@ -2102,13 +2174,13 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
case *ssa.MakeClosure:
|
||||
return b.parseMakeClosure(expr)
|
||||
case *ssa.MakeInterface:
|
||||
val := b.getValue(expr.X)
|
||||
val := b.getValue(expr.X, getPos(expr))
|
||||
return b.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil
|
||||
case *ssa.MakeMap:
|
||||
return b.createMakeMap(expr)
|
||||
case *ssa.MakeSlice:
|
||||
sliceLen := b.getValue(expr.Len)
|
||||
sliceCap := b.getValue(expr.Cap)
|
||||
sliceLen := b.getValue(expr.Len, getPos(expr))
|
||||
sliceCap := b.getValue(expr.Cap, getPos(expr))
|
||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||
llvmElemType := b.getLLVMType(sliceType.Elem())
|
||||
elemSize := b.targetData.TypeAllocSize(llvmElemType)
|
||||
@@ -2160,8 +2232,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
return slice, nil
|
||||
case *ssa.Next:
|
||||
rangeVal := expr.Iter.(*ssa.Range).X
|
||||
llvmRangeVal := b.getValue(rangeVal)
|
||||
it := b.getValue(expr.Iter)
|
||||
llvmRangeVal := b.getValue(rangeVal, getPos(expr))
|
||||
it := b.getValue(expr.Iter, getPos(expr))
|
||||
if expr.IsString {
|
||||
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
||||
} else { // map
|
||||
@@ -2187,14 +2259,14 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
case *ssa.Select:
|
||||
return b.createSelect(expr), nil
|
||||
case *ssa.Slice:
|
||||
value := b.getValue(expr.X)
|
||||
value := b.getValue(expr.X, getPos(expr))
|
||||
|
||||
var lowType, highType, maxType *types.Basic
|
||||
var low, high, max llvm.Value
|
||||
|
||||
if expr.Low != nil {
|
||||
lowType = expr.Low.Type().Underlying().(*types.Basic)
|
||||
low = b.getValue(expr.Low)
|
||||
low = b.getValue(expr.Low, getPos(expr))
|
||||
low = b.extendInteger(low, lowType, b.uintptrType)
|
||||
} else {
|
||||
lowType = types.Typ[types.Uintptr]
|
||||
@@ -2203,7 +2275,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
|
||||
if expr.High != nil {
|
||||
highType = expr.High.Type().Underlying().(*types.Basic)
|
||||
high = b.getValue(expr.High)
|
||||
high = b.getValue(expr.High, getPos(expr))
|
||||
high = b.extendInteger(high, highType, b.uintptrType)
|
||||
} else {
|
||||
highType = types.Typ[types.Uintptr]
|
||||
@@ -2211,7 +2283,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
|
||||
if expr.Max != nil {
|
||||
maxType = expr.Max.Type().Underlying().(*types.Basic)
|
||||
max = b.getValue(expr.Max)
|
||||
max = b.getValue(expr.Max, getPos(expr))
|
||||
max = b.extendInteger(max, maxType, b.uintptrType)
|
||||
} else {
|
||||
maxType = types.Typ[types.Uintptr]
|
||||
@@ -2344,7 +2416,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
// Conversion from a slice to an array pointer, as the name clearly
|
||||
// says. This requires a runtime check to make sure the slice is at
|
||||
// least as big as the array.
|
||||
slice := b.getValue(expr.X)
|
||||
slice := b.getValue(expr.X, getPos(expr))
|
||||
sliceLen := b.CreateExtractValue(slice, 1, "")
|
||||
arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()
|
||||
b.createSliceToArrayPointerCheck(sliceLen, arrayLen)
|
||||
@@ -2777,7 +2849,7 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
|
||||
}
|
||||
|
||||
// createConst creates a LLVM constant value from a Go constant.
|
||||
func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
||||
func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value {
|
||||
switch typ := expr.Type().Underlying().(type) {
|
||||
case *types.Basic:
|
||||
llvmType := c.getLLVMType(typ)
|
||||
@@ -2800,6 +2872,18 @@ func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetUnnamedAddr(true)
|
||||
global.SetAlignment(1)
|
||||
if c.Debug {
|
||||
// Unfortunately, expr.Pos() is always token.NoPos.
|
||||
position := c.program.Fset.Position(pos)
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
|
||||
File: c.getDIFile(position.Filename),
|
||||
Line: position.Line,
|
||||
Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(str)))),
|
||||
LocalToUnit: true,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
})
|
||||
global.AddMetadata(0, diglobal)
|
||||
}
|
||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
||||
strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero})
|
||||
} else {
|
||||
@@ -2823,15 +2907,15 @@ func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
||||
n, _ := constant.Float64Val(expr.Value)
|
||||
return llvm.ConstFloat(llvmType, n)
|
||||
} else if typ.Kind() == types.Complex64 {
|
||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
|
||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
|
||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]), pos)
|
||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]), pos)
|
||||
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false))
|
||||
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
|
||||
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
|
||||
return cplx
|
||||
} else if typ.Kind() == types.Complex128 {
|
||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
|
||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
|
||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]), pos)
|
||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]), pos)
|
||||
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false))
|
||||
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
|
||||
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
|
||||
@@ -2900,31 +2984,6 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
|
||||
if isPtrFrom && !isPtrTo {
|
||||
return b.CreatePtrToInt(value, llvmTypeTo, ""), nil
|
||||
} else if !isPtrFrom && isPtrTo {
|
||||
if !value.IsABinaryOperator().IsNil() && value.InstructionOpcode() == llvm.Add {
|
||||
// This is probably a pattern like the following:
|
||||
// unsafe.Pointer(uintptr(ptr) + index)
|
||||
// Used in functions like memmove etc. for lack of pointer
|
||||
// arithmetic. Convert it to real pointer arithmatic here.
|
||||
ptr := value.Operand(0)
|
||||
index := value.Operand(1)
|
||||
if !index.IsAPtrToIntInst().IsNil() {
|
||||
// Swap if necessary, if ptr and index are reversed.
|
||||
ptr, index = index, ptr
|
||||
}
|
||||
if !ptr.IsAPtrToIntInst().IsNil() {
|
||||
origptr := ptr.Operand(0)
|
||||
if origptr.Type() == b.i8ptrType {
|
||||
// This pointer can be calculated from the original
|
||||
// ptrtoint instruction with a GEP. The leftover inttoptr
|
||||
// instruction is trivial to optimize away.
|
||||
// Making it an in bounds GEP even though it's easy to
|
||||
// create a GEP that is not in bounds. However, we're
|
||||
// talking about unsafe code here so the programmer has to
|
||||
// be careful anyway.
|
||||
return b.CreateInBoundsGEP(b.ctx.Int8Type(), origptr, []llvm.Value{index}, ""), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return b.CreateIntToPtr(value, llvmTypeTo, ""), nil
|
||||
}
|
||||
|
||||
@@ -3127,7 +3186,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
|
||||
// which can all be directly lowered to IR. However, there is also the channel
|
||||
// receive operator which is handled in the runtime directly.
|
||||
func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
||||
x := b.getValue(unop.X)
|
||||
x := b.getValue(unop.X, getPos(unop))
|
||||
switch unop.Op {
|
||||
case token.NOT: // !x
|
||||
return b.CreateNot(x, ""), nil
|
||||
|
||||
+85
-43
@@ -70,52 +70,11 @@ func TestCompiler(t *testing.T) {
|
||||
options := &compileopts.Options{
|
||||
Target: targetString,
|
||||
}
|
||||
target, err := compileopts.LoadTarget(options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target:", err)
|
||||
}
|
||||
if tc.scheduler != "" {
|
||||
options.Scheduler = tc.scheduler
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: options,
|
||||
Target: target,
|
||||
}
|
||||
compilerConfig := &Config{
|
||||
Triple: config.Triple(),
|
||||
Features: config.Features(),
|
||||
ABI: config.ABI(),
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
defer machine.Dispose()
|
||||
|
||||
// Load entire program AST into memory.
|
||||
lprogram, err := loader.Load(config, "./testdata/"+tc.file, config.ClangHeaders, types.Config{
|
||||
Sizes: Sizes(machine),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
err = lprogram.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse test case %s: %s", tc.file, err)
|
||||
}
|
||||
|
||||
// Compile AST to IR.
|
||||
program := lprogram.LoadSSA()
|
||||
pkg := lprogram.MainPkg()
|
||||
mod, errs := CompilePackage(tc.file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
|
||||
mod, errs := testCompilePackage(t, options, tc.file)
|
||||
if errs != nil {
|
||||
for _, err := range errs {
|
||||
t.Error(err)
|
||||
@@ -123,7 +82,7 @@ func TestCompiler(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
err = llvm.VerifyModule(mod, llvm.PrintMessageAction)
|
||||
err := llvm.VerifyModule(mod, llvm.PrintMessageAction)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -216,3 +175,86 @@ func filterIrrelevantIRLines(lines []string) []string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestCompilerErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Read expected errors from the test file.
|
||||
var expectedErrors []string
|
||||
errorsFile, err := os.ReadFile("testdata/errors.go")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
errorsFileString := strings.ReplaceAll(string(errorsFile), "\r\n", "\n")
|
||||
for _, line := range strings.Split(errorsFileString, "\n") {
|
||||
if strings.HasPrefix(line, "// ERROR: ") {
|
||||
expectedErrors = append(expectedErrors, strings.TrimPrefix(line, "// ERROR: "))
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the Go file with errors.
|
||||
options := &compileopts.Options{
|
||||
Target: "wasm",
|
||||
}
|
||||
_, errs := testCompilePackage(t, options, "errors.go")
|
||||
|
||||
// Check whether the actual errors match the expected errors.
|
||||
expectedErrorsIdx := 0
|
||||
for _, err := range errs {
|
||||
err := err.(types.Error)
|
||||
position := err.Fset.Position(err.Pos)
|
||||
position.Filename = "errors.go" // don't use a full path
|
||||
if expectedErrorsIdx >= len(expectedErrors) || expectedErrors[expectedErrorsIdx] != err.Msg {
|
||||
t.Errorf("unexpected compiler error: %s: %s", position.String(), err.Msg)
|
||||
continue
|
||||
}
|
||||
expectedErrorsIdx++
|
||||
}
|
||||
}
|
||||
|
||||
// Build a package given a number of compiler options and a file.
|
||||
func testCompilePackage(t *testing.T, options *compileopts.Options, file string) (llvm.Module, []error) {
|
||||
target, err := compileopts.LoadTarget(options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target:", err)
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: options,
|
||||
Target: target,
|
||||
}
|
||||
compilerConfig := &Config{
|
||||
Triple: config.Triple(),
|
||||
Features: config.Features(),
|
||||
ABI: config.ABI(),
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
defer machine.Dispose()
|
||||
|
||||
// Load entire program AST into memory.
|
||||
lprogram, err := loader.Load(config, "./testdata/"+file, config.ClangHeaders, types.Config{
|
||||
Sizes: Sizes(machine),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
err = lprogram.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse test case %s: %s", file, err)
|
||||
}
|
||||
|
||||
// Compile AST to IR.
|
||||
program := lprogram.LoadSSA()
|
||||
pkg := lprogram.MainPkg()
|
||||
return CompilePackage(file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
|
||||
}
|
||||
|
||||
+9
-9
@@ -267,13 +267,13 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
|
||||
// Collect all values to be put in the struct (starting with
|
||||
// runtime._defer fields, followed by the call parameters).
|
||||
itf := b.getValue(instr.Call.Value) // interface
|
||||
itf := b.getValue(instr.Call.Value, getPos(instr)) // interface
|
||||
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
||||
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
||||
values = []llvm.Value{callback, next, typecode, receiverValue}
|
||||
valueTypes = append(valueTypes, b.i8ptrType, b.i8ptrType)
|
||||
for _, arg := range instr.Call.Args {
|
||||
val := b.getValue(arg)
|
||||
val := b.getValue(arg, getPos(instr))
|
||||
values = append(values, val)
|
||||
valueTypes = append(valueTypes, val.Type())
|
||||
}
|
||||
@@ -290,7 +290,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
// runtime._defer fields).
|
||||
values = []llvm.Value{callback, next}
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam := b.getValue(param)
|
||||
llvmParam := b.getValue(param, getPos(instr))
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
@@ -302,7 +302,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
// pointer.
|
||||
// TODO: ignore this closure entirely and put pointers to the free
|
||||
// variables directly in the defer struct, avoiding a memory allocation.
|
||||
closure := b.getValue(instr.Call.Value)
|
||||
closure := b.getValue(instr.Call.Value, getPos(instr))
|
||||
context := b.CreateExtractValue(closure, 0, "")
|
||||
|
||||
// Get the callback number.
|
||||
@@ -318,7 +318,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
// context pointer).
|
||||
values = []llvm.Value{callback, next}
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam := b.getValue(param)
|
||||
llvmParam := b.getValue(param, getPos(instr))
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
var argValues []llvm.Value
|
||||
for _, arg := range instr.Call.Args {
|
||||
argTypes = append(argTypes, arg.Type())
|
||||
argValues = append(argValues, b.getValue(arg))
|
||||
argValues = append(argValues, b.getValue(arg, getPos(instr)))
|
||||
}
|
||||
|
||||
if _, ok := b.deferBuiltinFuncs[instr.Call.Value]; !ok {
|
||||
@@ -353,7 +353,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
}
|
||||
|
||||
} else {
|
||||
funcValue := b.getValue(instr.Call.Value)
|
||||
funcValue := b.getValue(instr.Call.Value, getPos(instr))
|
||||
|
||||
if _, ok := b.deferExprFuncs[instr.Call.Value]; !ok {
|
||||
b.deferExprFuncs[instr.Call.Value] = len(b.allDeferFuncs)
|
||||
@@ -368,7 +368,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
values = []llvm.Value{callback, next, funcValue}
|
||||
valueTypes = append(valueTypes, funcValue.Type())
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam := b.getValue(param)
|
||||
llvmParam := b.getValue(param, getPos(instr))
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
@@ -544,7 +544,7 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, forwardParam)
|
||||
}
|
||||
|
||||
// Plain TinyGo functions add some extra parameters to implement async functionality and function recievers.
|
||||
// Plain TinyGo functions add some extra parameters to implement async functionality and function receivers.
|
||||
// These parameters should not be supplied when calling into an external C/ASM function.
|
||||
if !b.getFunctionInfo(callback).exported {
|
||||
// Add the context parameter. We know it is ignored by the receiving
|
||||
|
||||
+3
-2
@@ -32,7 +32,8 @@ func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context
|
||||
// global reference is not real, it is only used during func lowering to assign
|
||||
// signature types to functions and will then be removed.
|
||||
func (c *compilerContext) getFuncSignatureID(sig *types.Signature) llvm.Value {
|
||||
sigGlobalName := "reflect/types.funcid:" + getTypeCodeName(sig)
|
||||
s, _ := getTypeCodeName(sig)
|
||||
sigGlobalName := "reflect/types.funcid:" + s
|
||||
sigGlobal := c.mod.NamedGlobal(sigGlobalName)
|
||||
if sigGlobal.IsNil() {
|
||||
sigGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), sigGlobalName)
|
||||
@@ -134,7 +135,7 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
|
||||
boundVars := make([]llvm.Value, len(expr.Bindings))
|
||||
for i, binding := range expr.Bindings {
|
||||
// The context stores the bound variables.
|
||||
llvmBoundVar := b.getValue(binding)
|
||||
llvmBoundVar := b.getValue(binding, getPos(expr))
|
||||
boundVars[i] = llvmBoundVar
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
// Get all function parameters to pass to the goroutine.
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Call.Args {
|
||||
params = append(params, b.getValue(param))
|
||||
params = append(params, b.getValue(param, getPos(instr)))
|
||||
}
|
||||
|
||||
var prefix string
|
||||
@@ -33,7 +33,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
case *ssa.MakeClosure:
|
||||
// A goroutine call on a func value, but the callee is trivial to find. For
|
||||
// example: immediately applied functions.
|
||||
funcValue := b.getValue(value)
|
||||
funcValue := b.getValue(value, getPos(instr))
|
||||
context = b.extractFuncContext(funcValue)
|
||||
default:
|
||||
panic("StaticCallee returned an unexpected value")
|
||||
@@ -70,13 +70,13 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
var argValues []llvm.Value
|
||||
for _, arg := range instr.Call.Args {
|
||||
argTypes = append(argTypes, arg.Type())
|
||||
argValues = append(argValues, b.getValue(arg))
|
||||
argValues = append(argValues, b.getValue(arg, getPos(instr)))
|
||||
}
|
||||
b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos())
|
||||
return
|
||||
} else if instr.Call.IsInvoke() {
|
||||
// This is a method call on an interface value.
|
||||
itf := b.getValue(instr.Call.Value)
|
||||
itf := b.getValue(instr.Call.Value, getPos(instr))
|
||||
itfTypeCode := b.CreateExtractValue(itf, 0, "")
|
||||
itfValue := b.CreateExtractValue(itf, 1, "")
|
||||
funcPtr = b.getInvokeFunction(&instr.Call)
|
||||
@@ -90,7 +90,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
// * The function context, for closures.
|
||||
// * The function pointer (for tasks).
|
||||
var context llvm.Value
|
||||
funcPtrType, funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||
funcPtrType, funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)), instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||
params = append(params, context, funcPtr)
|
||||
hasContext = true
|
||||
prefix = b.fn.RelString(nil)
|
||||
|
||||
@@ -5,6 +5,7 @@ package compiler
|
||||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -55,7 +56,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return llvm.Value{}, b.makeError(instr.Pos(), "register value map must be created in the same basic block")
|
||||
}
|
||||
key := constant.StringVal(r.Key.(*ssa.Const).Value)
|
||||
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X)
|
||||
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X, getPos(instr))
|
||||
case *ssa.Call:
|
||||
if r.Common() == instr {
|
||||
break
|
||||
@@ -140,7 +141,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
//
|
||||
// The num parameter must be a constant. All other parameters may be any scalar
|
||||
// value supported by LLVM inline assembly.
|
||||
func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
|
||||
func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
|
||||
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
|
||||
llvmArgs := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
@@ -153,7 +154,7 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
|
||||
} else {
|
||||
constraints += ",{r" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, pos)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -178,7 +179,7 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
|
||||
// The num parameter must be a constant. All other parameters may be any scalar
|
||||
// value supported by LLVM inline assembly.
|
||||
// Same as emitSVCall but for AArch64
|
||||
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
|
||||
func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
|
||||
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
|
||||
llvmArgs := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
@@ -191,7 +192,7 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
|
||||
} else {
|
||||
constraints += ",{x" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, pos)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -231,19 +232,19 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrw %d, $0", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
|
||||
case "SetBits":
|
||||
// Note: it may be possible to optimize this to csrrsi in many cases.
|
||||
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
|
||||
case "ClearBits":
|
||||
// Note: it may be possible to optimize this to csrrci in many cases.
|
||||
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
|
||||
}
|
||||
|
||||
+235
-39
@@ -6,6 +6,7 @@ package compiler
|
||||
// interface-lowering.go for more details.
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@@ -57,6 +58,15 @@ const (
|
||||
structFieldFlagAnonymous = 1 << iota
|
||||
structFieldFlagHasTag
|
||||
structFieldFlagIsExported
|
||||
structFieldFlagIsEmbedded
|
||||
)
|
||||
|
||||
type reflectChanDir int
|
||||
|
||||
const (
|
||||
refRecvDir reflectChanDir = 1 << iota // <-chan
|
||||
refSendDir // chan<-
|
||||
refBothDir = refRecvDir | refSendDir // chan
|
||||
)
|
||||
|
||||
// createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction.
|
||||
@@ -83,6 +93,30 @@ func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type)
|
||||
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
|
||||
}
|
||||
|
||||
func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
|
||||
pkgpathName := "reflect/types.type.pkgpath.empty"
|
||||
if pkgpath != "" {
|
||||
pkgpathName = "reflect/types.type.pkgpath:" + pkgpath
|
||||
}
|
||||
|
||||
pkgpathGlobal := c.mod.NamedGlobal(pkgpathName)
|
||||
if pkgpathGlobal.IsNil() {
|
||||
pkgpathInitializer := c.ctx.ConstString(pkgpath+"\x00", false)
|
||||
pkgpathGlobal = llvm.AddGlobal(c.mod, pkgpathInitializer.Type(), pkgpathName)
|
||||
pkgpathGlobal.SetInitializer(pkgpathInitializer)
|
||||
pkgpathGlobal.SetAlignment(1)
|
||||
pkgpathGlobal.SetUnnamedAddr(true)
|
||||
pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
pkgpathGlobal.SetGlobalConstant(true)
|
||||
}
|
||||
pkgPathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
})
|
||||
|
||||
return pkgPathPtr
|
||||
}
|
||||
|
||||
// getTypeCode returns a reference to a type code.
|
||||
// A type code is a pointer to a constant global that describes the type.
|
||||
// This function returns a pointer to the 'kind' field (which might not be the
|
||||
@@ -93,8 +127,39 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
if _, ok := typ.Underlying().(*types.Interface); ok {
|
||||
hasMethodSet = false
|
||||
}
|
||||
globalName := "reflect/types.type:" + getTypeCodeName(typ)
|
||||
global := c.mod.NamedGlobal(globalName)
|
||||
|
||||
// Short-circuit all the global pointer logic here for pointers to pointers.
|
||||
if typ, ok := typ.(*types.Pointer); ok {
|
||||
if _, ok := typ.Elem().(*types.Pointer); ok {
|
||||
// For a pointer to a pointer, we just increase the pointer by 1
|
||||
ptr := c.getTypeCode(typ.Elem())
|
||||
// if the type is already *****T or higher, we can't make it.
|
||||
if typstr := typ.String(); strings.HasPrefix(typstr, "*****") {
|
||||
c.addError(token.NoPos, fmt.Sprintf("too many levels of pointers for typecode: %s", typstr))
|
||||
}
|
||||
return llvm.ConstGEP(c.ctx.Int8Type(), ptr, []llvm.Value{
|
||||
llvm.ConstInt(llvm.Int32Type(), 1, false),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
typeCodeName, isLocal := getTypeCodeName(typ)
|
||||
globalName := "reflect/types.type:" + typeCodeName
|
||||
var global llvm.Value
|
||||
if isLocal {
|
||||
// This type is a named type inside a function, like this:
|
||||
//
|
||||
// func foo() any {
|
||||
// type named int
|
||||
// return named(0)
|
||||
// }
|
||||
if obj := c.interfaceTypes.At(typ); obj != nil {
|
||||
global = obj.(llvm.Value)
|
||||
}
|
||||
} else {
|
||||
// Regular type (named or otherwise).
|
||||
global = c.mod.NamedGlobal(globalName)
|
||||
}
|
||||
if global.IsNil() {
|
||||
var typeFields []llvm.Value
|
||||
// Define the type fields. These must match the structs in
|
||||
@@ -109,35 +174,56 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
case *types.Named:
|
||||
name := typ.Obj().Name()
|
||||
var pkgname string
|
||||
if pkg := typ.Obj().Pkg(); pkg != nil {
|
||||
pkgname = pkg.Name()
|
||||
}
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
|
||||
)
|
||||
case *types.Chan, *types.Slice:
|
||||
case *types.Chan:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), // reuse for select chan direction
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
case *types.Slice:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
case *types.Pointer:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
case *types.Array:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
|
||||
)
|
||||
case *types.Map:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "keyType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
case *types.Struct:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uint32]),
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
)
|
||||
case *types.Interface:
|
||||
@@ -164,49 +250,105 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}
|
||||
globalType := types.NewStruct(typeFieldTypes, nil)
|
||||
global = llvm.AddGlobal(c.mod, c.getLLVMType(globalType), globalName)
|
||||
if isLocal {
|
||||
c.interfaceTypes.Set(typ, global)
|
||||
}
|
||||
metabyte := getTypeKind(typ)
|
||||
|
||||
// Precompute these so we don't have to calculate them at runtime.
|
||||
if types.Comparable(typ) {
|
||||
metabyte |= 1 << 6
|
||||
}
|
||||
|
||||
if hashmapIsBinaryKey(typ) {
|
||||
metabyte |= 1 << 7
|
||||
}
|
||||
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
case *types.Named:
|
||||
name := typ.Obj().Name()
|
||||
var pkgpath string
|
||||
var pkgname string
|
||||
if pkg := typ.Obj().Pkg(); pkg != nil {
|
||||
pkgpath = pkg.Path()
|
||||
pkgname = pkg.Name()
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
case *types.Chan:
|
||||
var dir reflectChanDir
|
||||
switch typ.Dir() {
|
||||
case types.SendRecv:
|
||||
dir = refBothDir
|
||||
case types.RecvOnly:
|
||||
dir = refRecvDir
|
||||
case types.SendOnly:
|
||||
dir = refSendDir
|
||||
}
|
||||
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(dir), false), // actually channel direction
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
}
|
||||
case *types.Slice:
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
}
|
||||
case *types.Pointer:
|
||||
typeFields = []llvm.Value{c.getTypeCode(typ.Elem())}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(typ.Elem()),
|
||||
}
|
||||
case *types.Array:
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false), // length
|
||||
}
|
||||
case *types.Map:
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elem
|
||||
c.getTypeCode(typ.Key()), // key
|
||||
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Elem()), // elem
|
||||
c.getTypeCode(typ.Key()), // key
|
||||
}
|
||||
case *types.Struct:
|
||||
var pkgpath string
|
||||
if typ.NumFields() > 0 {
|
||||
if pkg := typ.Field(0).Pkg(); pkg != nil {
|
||||
pkgpath = pkg.Path()
|
||||
}
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
|
||||
llvmStructType := c.getLLVMType(typ)
|
||||
size := c.targetData.TypeStoreSize(llvmStructType)
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
pkgPathPtr,
|
||||
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
}
|
||||
structFieldType := c.getLLVMRuntimeType("structField")
|
||||
|
||||
var fields []llvm.Value
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
field := typ.Field(i)
|
||||
offset := c.targetData.ElementOffset(llvmStructType, i)
|
||||
var flags uint8
|
||||
if field.Anonymous() {
|
||||
flags |= structFieldFlagAnonymous
|
||||
@@ -217,7 +359,14 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
if token.IsExported(field.Name()) {
|
||||
flags |= structFieldFlagIsExported
|
||||
}
|
||||
data := string(flags) + field.Name() + "\x00"
|
||||
if field.Embedded() {
|
||||
flags |= structFieldFlagIsEmbedded
|
||||
}
|
||||
|
||||
var offsBytes [binary.MaxVarintLen32]byte
|
||||
offLen := binary.PutUvarint(offsBytes[:], offset)
|
||||
|
||||
data := string(flags) + string(offsBytes[:offLen]) + field.Name() + "\x00"
|
||||
if typ.Tag(i) != "" {
|
||||
if len(typ.Tag(i)) > 0xff {
|
||||
c.addError(field.Pos(), fmt.Sprintf("struct tag is %d bytes which is too long, max is 255", len(typ.Tag(i))))
|
||||
@@ -258,9 +407,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}, typeFields...)
|
||||
}
|
||||
alignment := c.targetData.TypeAllocSize(c.i8ptrType)
|
||||
if alignment < 4 {
|
||||
alignment = 4
|
||||
}
|
||||
globalValue := c.ctx.ConstStruct(typeFields, false)
|
||||
global.SetInitializer(globalValue)
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
if isLocal {
|
||||
global.SetLinkage(llvm.InternalLinkage)
|
||||
} else {
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetAlignment(int(alignment))
|
||||
if c.Debug {
|
||||
@@ -341,57 +497,94 @@ var basicTypeNames = [...]string{
|
||||
// getTypeCodeName returns a name for this type that can be used in the
|
||||
// interface lowering pass to assign type codes as expected by the reflect
|
||||
// package. See getTypeCodeNum.
|
||||
func getTypeCodeName(t types.Type) string {
|
||||
func getTypeCodeName(t types.Type) (string, bool) {
|
||||
switch t := t.(type) {
|
||||
case *types.Named:
|
||||
return "named:" + t.String()
|
||||
// Note: check for `t.Obj().Pkg() != nil` for Go 1.18 only.
|
||||
if t.Obj().Pkg() != nil && t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
||||
return "named:" + t.String() + "$local", true
|
||||
}
|
||||
return "named:" + t.String(), false
|
||||
case *types.Array:
|
||||
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + s, isLocal
|
||||
case *types.Basic:
|
||||
return "basic:" + basicTypeNames[t.Kind()]
|
||||
return "basic:" + basicTypeNames[t.Kind()], false
|
||||
case *types.Chan:
|
||||
return "chan:" + getTypeCodeName(t.Elem())
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
var dir string
|
||||
switch t.Dir() {
|
||||
case types.SendOnly:
|
||||
dir = "s:"
|
||||
case types.RecvOnly:
|
||||
dir = "r:"
|
||||
case types.SendRecv:
|
||||
dir = "sr:"
|
||||
}
|
||||
|
||||
return "chan:" + dir + s, isLocal
|
||||
case *types.Interface:
|
||||
isLocal := false
|
||||
methods := make([]string, t.NumMethods())
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
name := t.Method(i).Name()
|
||||
if !token.IsExported(name) {
|
||||
name = t.Method(i).Pkg().Path() + "." + name
|
||||
}
|
||||
methods[i] = name + ":" + getTypeCodeName(t.Method(i).Type())
|
||||
s, local := getTypeCodeName(t.Method(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
methods[i] = name + ":" + s
|
||||
}
|
||||
return "interface:" + "{" + strings.Join(methods, ",") + "}"
|
||||
return "interface:" + "{" + strings.Join(methods, ",") + "}", isLocal
|
||||
case *types.Map:
|
||||
keyType := getTypeCodeName(t.Key())
|
||||
elemType := getTypeCodeName(t.Elem())
|
||||
return "map:" + "{" + keyType + "," + elemType + "}"
|
||||
keyType, keyLocal := getTypeCodeName(t.Key())
|
||||
elemType, elemLocal := getTypeCodeName(t.Elem())
|
||||
return "map:" + "{" + keyType + "," + elemType + "}", keyLocal || elemLocal
|
||||
case *types.Pointer:
|
||||
return "pointer:" + getTypeCodeName(t.Elem())
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
return "pointer:" + s, isLocal
|
||||
case *types.Signature:
|
||||
isLocal := false
|
||||
params := make([]string, t.Params().Len())
|
||||
for i := 0; i < t.Params().Len(); i++ {
|
||||
params[i] = getTypeCodeName(t.Params().At(i).Type())
|
||||
s, local := getTypeCodeName(t.Params().At(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
params[i] = s
|
||||
}
|
||||
results := make([]string, t.Results().Len())
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
results[i] = getTypeCodeName(t.Results().At(i).Type())
|
||||
s, local := getTypeCodeName(t.Results().At(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
results[i] = s
|
||||
}
|
||||
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}"
|
||||
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}", isLocal
|
||||
case *types.Slice:
|
||||
return "slice:" + getTypeCodeName(t.Elem())
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
return "slice:" + s, isLocal
|
||||
case *types.Struct:
|
||||
elems := make([]string, t.NumFields())
|
||||
isLocal := false
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
embedded := ""
|
||||
if t.Field(i).Embedded() {
|
||||
embedded = "#"
|
||||
}
|
||||
elems[i] = embedded + t.Field(i).Name() + ":" + getTypeCodeName(t.Field(i).Type())
|
||||
s, local := getTypeCodeName(t.Field(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
elems[i] = embedded + t.Field(i).Name() + ":" + s
|
||||
if t.Tag(i) != "" {
|
||||
elems[i] += "`" + t.Tag(i) + "`"
|
||||
}
|
||||
}
|
||||
return "struct:" + "{" + strings.Join(elems, ",") + "}"
|
||||
return "struct:" + "{" + strings.Join(elems, ",") + "}", isLocal
|
||||
default:
|
||||
panic("unknown type: " + t.String())
|
||||
}
|
||||
@@ -475,7 +668,7 @@ func (c *compilerContext) getMethodSignature(method *types.Func) llvm.Value {
|
||||
// Type asserts on concrete types are trivial: just compare type numbers. Type
|
||||
// asserts on interfaces are more difficult, see the comments in the function.
|
||||
func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
itf := b.getValue(expr.X)
|
||||
itf := b.getValue(expr.X, getPos(expr))
|
||||
assertedType := b.getLLVMType(expr.AssertedType)
|
||||
|
||||
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
||||
@@ -494,7 +687,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||
|
||||
} else {
|
||||
globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
|
||||
name, _ := getTypeCodeName(expr.AssertedType)
|
||||
globalName := "reflect/types.typeid:" + name
|
||||
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
||||
if assertedTypeCodeGlobal.IsNil() {
|
||||
// Create a new typecode global.
|
||||
@@ -567,10 +761,11 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
return strings.Join(methods, "; ")
|
||||
}
|
||||
|
||||
// getInterfaceImplementsfunc returns a declared function that works as a type
|
||||
// getInterfaceImplementsFunc returns a declared function that works as a type
|
||||
// switch. The interface lowering pass will define this function.
|
||||
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
|
||||
fnName := getTypeCodeName(assertedType.Underlying()) + ".$typeassert"
|
||||
s, _ := getTypeCodeName(assertedType.Underlying())
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.i8ptrType}, false)
|
||||
@@ -586,7 +781,8 @@ func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) ll
|
||||
// thunk is declared, not defined: it will be defined by the interface lowering
|
||||
// pass.
|
||||
func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
||||
fnName := getTypeCodeName(instr.Value.Type().Underlying()) + "." + instr.Method.Name() + "$invoke"
|
||||
s, _ := getTypeCodeName(instr.Value.Type().Underlying())
|
||||
fnName := s + "." + instr.Method.Name() + "$invoke"
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
sig := instr.Method.Type().(*types.Signature)
|
||||
|
||||
@@ -24,7 +24,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
|
||||
// Note that bound functions are allowed if the function has a pointer
|
||||
// receiver and is a global. This is rather strict but still allows for
|
||||
// idiomatic Go code.
|
||||
funcValue := b.getValue(instr.Args[1])
|
||||
funcValue := b.getValue(instr.Args[1], getPos(instr))
|
||||
if funcValue.IsAConstant().IsNil() {
|
||||
// Try to determine the cause of the non-constantness for a nice error
|
||||
// message.
|
||||
|
||||
+120
-5
@@ -58,7 +58,7 @@ func (b *builder) createMemoryCopyImpl() {
|
||||
}
|
||||
var params []llvm.Value
|
||||
for _, param := range b.fn.Params {
|
||||
params = append(params, b.getValue(param))
|
||||
params = append(params, b.getValue(param, getPos(b.fn)))
|
||||
}
|
||||
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
|
||||
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
|
||||
@@ -80,9 +80,9 @@ func (b *builder) createMemoryZeroImpl() {
|
||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
||||
}
|
||||
params := []llvm.Value{
|
||||
b.getValue(b.fn.Params[0]),
|
||||
b.getValue(b.fn.Params[0], getPos(b.fn)),
|
||||
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
||||
b.getValue(b.fn.Params[1]),
|
||||
b.getValue(b.fn.Params[1], getPos(b.fn)),
|
||||
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
|
||||
}
|
||||
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
|
||||
@@ -95,7 +95,7 @@ func (b *builder) createKeepAliveImpl() {
|
||||
b.createFunctionStart(true)
|
||||
|
||||
// Get the underlying value of the interface value.
|
||||
interfaceValue := b.getValue(b.fn.Params[0])
|
||||
interfaceValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
pointerValue := b.CreateExtractValue(interfaceValue, 1, "")
|
||||
|
||||
// Create an equivalent of the following C code, which is basically just a
|
||||
@@ -149,8 +149,123 @@ func (b *builder) defineMathOp() {
|
||||
// Create a call to the intrinsic.
|
||||
args := make([]llvm.Value, len(b.fn.Params))
|
||||
for i, param := range b.fn.Params {
|
||||
args[i] = b.getValue(param)
|
||||
args[i] = b.getValue(param, getPos(b.fn))
|
||||
}
|
||||
result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "")
|
||||
b.CreateRet(result)
|
||||
}
|
||||
|
||||
// Implement most math/bits functions.
|
||||
//
|
||||
// This implements all the functions that operate on bits. It does not yet
|
||||
// implement the arithmetic functions (like bits.Add), which also have LLVM
|
||||
// intrinsics.
|
||||
func (b *builder) defineMathBitsIntrinsic() bool {
|
||||
if b.fn.Pkg.Pkg.Path() != "math/bits" {
|
||||
return false
|
||||
}
|
||||
name := b.fn.Name()
|
||||
switch name {
|
||||
case "LeadingZeros", "LeadingZeros8", "LeadingZeros16", "LeadingZeros32", "LeadingZeros64",
|
||||
"TrailingZeros", "TrailingZeros8", "TrailingZeros16", "TrailingZeros32", "TrailingZeros64":
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
valueType := param.Type()
|
||||
var intrinsicName string
|
||||
if strings.HasPrefix(name, "Leading") { // LeadingZeros
|
||||
intrinsicName = "llvm.ctlz.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
} else { // TrailingZeros
|
||||
intrinsicName = "llvm.cttz.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
}
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
|
||||
}
|
||||
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
|
||||
param,
|
||||
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
|
||||
}, "")
|
||||
result = b.createZExtOrTrunc(result, b.intType)
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
case "Len", "Len8", "Len16", "Len32", "Len64":
|
||||
// bits.Len can be implemented as:
|
||||
// (unsafe.Sizeof(v) * 8) - bits.LeadingZeros(n)
|
||||
// Not sure why this isn't already done in the standard library, as it
|
||||
// is much simpler than a lookup table.
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
valueType := param.Type()
|
||||
valueBits := valueType.IntTypeWidth()
|
||||
intrinsicName := "llvm.ctlz.i" + strconv.Itoa(valueBits)
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
|
||||
}
|
||||
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
|
||||
param,
|
||||
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
|
||||
}, "")
|
||||
result = b.createZExtOrTrunc(result, b.intType)
|
||||
maxLen := llvm.ConstInt(b.intType, uint64(valueBits), false) // number of bits in the value
|
||||
result = b.CreateSub(maxLen, result, "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
case "OnesCount", "OnesCount8", "OnesCount16", "OnesCount32", "OnesCount64":
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
valueType := param.Type()
|
||||
intrinsicName := "llvm.ctpop.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
|
||||
}
|
||||
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
|
||||
result = b.createZExtOrTrunc(result, b.intType)
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
case "Reverse", "Reverse8", "Reverse16", "Reverse32", "Reverse64",
|
||||
"ReverseBytes", "ReverseBytes16", "ReverseBytes32", "ReverseBytes64":
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
valueType := param.Type()
|
||||
var intrinsicName string
|
||||
if strings.HasPrefix(name, "ReverseBytes") {
|
||||
intrinsicName = "llvm.bswap.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
} else { // Reverse
|
||||
intrinsicName = "llvm.bitreverse.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
}
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
|
||||
}
|
||||
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
case "RotateLeft", "RotateLeft8", "RotateLeft16", "RotateLeft32", "RotateLeft64":
|
||||
// Warning: the documentation says these functions must be constant time.
|
||||
// I do not think LLVM guarantees this, but there's a good chance LLVM
|
||||
// already recognized the rotate instruction so it probably won't get
|
||||
// any _worse_ by implementing these rotate functions.
|
||||
b.createFunctionStart(true)
|
||||
x := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
k := b.getValue(b.fn.Params[1], b.fn.Pos())
|
||||
valueType := x.Type()
|
||||
intrinsicName := "llvm.fshl.i" + strconv.Itoa(valueType.IntTypeWidth())
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, valueType, valueType}, false)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
|
||||
}
|
||||
k = b.createZExtOrTrunc(k, valueType)
|
||||
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{x, x, k}, "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,6 +464,19 @@ func (b *builder) readStackPointer() llvm.Value {
|
||||
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
|
||||
}
|
||||
|
||||
// createZExtOrTrunc lets the input value fit in the output type bits, by zero
|
||||
// extending or truncating the integer.
|
||||
func (b *builder) createZExtOrTrunc(value llvm.Value, t llvm.Type) llvm.Value {
|
||||
valueBits := value.Type().IntTypeWidth()
|
||||
resultBits := t.IntTypeWidth()
|
||||
if valueBits > resultBits {
|
||||
value = b.CreateTrunc(value, t, "")
|
||||
} else if valueBits < resultBits {
|
||||
value = b.CreateZExt(value, t, "")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Reverse a slice of bytes. From the wiki:
|
||||
// https://github.com/golang/go/wiki/SliceTricks#reversing
|
||||
func reverseBytes(buf []byte) {
|
||||
|
||||
+7
-4
@@ -46,7 +46,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
|
||||
if expr.Reserve != nil {
|
||||
sizeHint = b.getValue(expr.Reserve)
|
||||
sizeHint = b.getValue(expr.Reserve, getPos(expr))
|
||||
var err error
|
||||
sizeHint, err = b.createConvert(expr.Reserve.Type(), types.Typ[types.Uintptr], sizeHint, expr.Pos())
|
||||
if err != nil {
|
||||
@@ -78,6 +78,7 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
||||
|
||||
// Do the lookup. How it is done depends on the key type.
|
||||
var commaOkValue llvm.Value
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
@@ -99,7 +100,7 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface now.
|
||||
itfKey = b.createMakeInterface(key, keyType, pos)
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, mapValuePtr, mapValueSize}
|
||||
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
|
||||
@@ -125,6 +126,7 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
||||
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
||||
valueAlloca, valuePtr, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
|
||||
b.CreateStore(value, valueAlloca)
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
@@ -143,7 +145,7 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = b.createMakeInterface(key, keyType, pos)
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, valuePtr}
|
||||
b.createRuntimeCall("hashmapInterfaceSet", params, "")
|
||||
@@ -154,6 +156,7 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
|
||||
// createMapDelete deletes a key from a map by calling the appropriate runtime
|
||||
// function. It is the implementation of the Go delete() builtin.
|
||||
func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
@@ -174,7 +177,7 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = b.createMakeInterface(key, keyType, pos)
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey}
|
||||
b.createRuntimeCall("hashmapInterfaceDelete", params, "")
|
||||
|
||||
+101
-6
@@ -4,6 +4,7 @@ package compiler
|
||||
// pragmas, determines the link name, etc.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@@ -52,6 +53,17 @@ const (
|
||||
inlineNone
|
||||
)
|
||||
|
||||
// Values for the allockind attribute. Source:
|
||||
// https://github.com/llvm/llvm-project/blob/release/16.x/llvm/include/llvm/IR/Attributes.h#L49
|
||||
const (
|
||||
allocKindAlloc = 1 << iota
|
||||
allocKindRealloc
|
||||
allocKindFree
|
||||
allocKindUninitialized
|
||||
allocKindZeroed
|
||||
allocKindAligned
|
||||
)
|
||||
|
||||
// getFunction returns the LLVM function for the given *ssa.Function, creating
|
||||
// it if needed. It can later be filled with compilerContext.createFunction().
|
||||
func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) {
|
||||
@@ -133,6 +145,20 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
for _, attrName := range []string{"noalias", "nonnull"} {
|
||||
llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
|
||||
}
|
||||
if llvmutil.Major() >= 15 { // allockind etc are not available in LLVM 14
|
||||
// Add attributes to signal to LLVM that this is an allocator
|
||||
// function. This enables a number of optimizations.
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allockind"), allocKindAlloc|allocKindZeroed))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("alloc-family", "runtime.alloc"))
|
||||
// Use a special value to indicate the first parameter:
|
||||
// > allocsize has two integer arguments, but because they're both 32 bits, we can
|
||||
// > pack them into one 64-bit value, at the cost of making said value
|
||||
// > nonsensical.
|
||||
// >
|
||||
// > In order to do this, we need to reserve one value of the second (optional)
|
||||
// > allocsize argument to signify "not present."
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allocsize"), 0x0000_0000_ffff_ffff))
|
||||
}
|
||||
case "runtime.sliceAppend":
|
||||
// Appending a slice will only read the to-be-appended slice, it won't
|
||||
// be modified.
|
||||
@@ -214,18 +240,22 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// present in *ssa.Function, such as the link name and whether it should be
|
||||
// exported.
|
||||
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
if info, ok := c.functionInfos[f]; ok {
|
||||
return info
|
||||
}
|
||||
info := functionInfo{
|
||||
// Pick the default linkName.
|
||||
linkName: f.RelString(nil),
|
||||
}
|
||||
// Check for //go: pragmas, which may change the link name (among others).
|
||||
info.parsePragmas(f)
|
||||
c.parsePragmas(&info, f)
|
||||
c.functionInfos[f] = info
|
||||
return info
|
||||
}
|
||||
|
||||
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
|
||||
// //export or //go:noinline.
|
||||
func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
if f.Syntax() == nil {
|
||||
return
|
||||
}
|
||||
@@ -263,6 +293,17 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
continue
|
||||
}
|
||||
info.module = parts[1]
|
||||
case "//go:wasmimport":
|
||||
// Import a WebAssembly function, for example a WASI function.
|
||||
// Original proposal: https://github.com/golang/go/issues/38248
|
||||
// Allow globally: https://github.com/golang/go/issues/59149
|
||||
if len(parts) != 3 {
|
||||
continue
|
||||
}
|
||||
c.checkWasmImport(f, comment.Text)
|
||||
info.exported = true
|
||||
info.module = parts[1]
|
||||
info.importName = parts[2]
|
||||
case "//go:inline":
|
||||
info.inline = inlineHint
|
||||
case "//go:noinline":
|
||||
@@ -279,8 +320,12 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
info.linkName = parts[2]
|
||||
}
|
||||
case "//go:section":
|
||||
// Only enable go:section when the package imports "unsafe".
|
||||
// go:section also implies go:noinline since inlining could
|
||||
// move the code to a different section than that requested.
|
||||
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.section = parts[1]
|
||||
info.inline = inlineNone
|
||||
}
|
||||
case "//go:nobounds":
|
||||
// Skip bounds checking in this function. Useful for some
|
||||
@@ -316,6 +361,58 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether this function cannot be used in //go:wasmimport. It will add an
|
||||
// error if this is the case.
|
||||
//
|
||||
// The list of allowed types is based on this proposal:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
||||
if c.pkg.Path() == "runtime" {
|
||||
// The runtime is a special case. Allow all kinds of parameters
|
||||
// (importantly, including pointers).
|
||||
return
|
||||
}
|
||||
if f.Blocks != nil {
|
||||
// Defined functions cannot be exported.
|
||||
c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
|
||||
return
|
||||
}
|
||||
if f.Signature.Results().Len() > 1 {
|
||||
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
|
||||
} else if f.Signature.Results().Len() == 1 {
|
||||
result := f.Signature.Results().At(0)
|
||||
if !isValidWasmType(result.Type(), true) {
|
||||
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
|
||||
}
|
||||
}
|
||||
for _, param := range f.Params {
|
||||
// Check whether the type is allowed.
|
||||
// Only a very limited number of types can be mapped to WebAssembly.
|
||||
if !isValidWasmType(param.Type(), false) {
|
||||
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the type maps directly to a WebAssembly type, according to:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func isValidWasmType(typ types.Type, isReturn bool) bool {
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch typ.Kind() {
|
||||
case types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
return true
|
||||
case types.Float32, types.Float64:
|
||||
return true
|
||||
case types.UnsafePointer:
|
||||
if !isReturn {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getParams returns the function parameters, including the receiver at the
|
||||
// start. This is an alternative to the Params member of *ssa.Function, which is
|
||||
// not yet populated when the package has not yet been built.
|
||||
@@ -379,7 +476,7 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
|
||||
}
|
||||
}
|
||||
|
||||
// addStandardAttribute adds all attributes added to defined functions.
|
||||
// addStandardAttributes adds all attributes added to defined functions.
|
||||
func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
c.addStandardDefinedAttributes(llvmFn)
|
||||
@@ -433,7 +530,6 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||
llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName)
|
||||
|
||||
// Set alignment from the //go:align comment.
|
||||
var alignInBits uint32
|
||||
alignment := c.targetData.ABITypeAlignment(llvmType)
|
||||
if info.align > alignment {
|
||||
alignment = info.align
|
||||
@@ -444,7 +540,6 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||
c.addError(g.Pos(), "global variable alignment must be a positive power of two")
|
||||
} else {
|
||||
// Set the alignment only when it is a power of two.
|
||||
alignInBits = uint32(alignment) ^ uint32(alignment-1)
|
||||
llvmGlobal.SetAlignment(alignment)
|
||||
}
|
||||
|
||||
@@ -459,7 +554,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||
Type: c.getDIType(typ),
|
||||
LocalToUnit: false,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
AlignInBits: alignInBits,
|
||||
AlignInBits: uint32(alignment) * 8,
|
||||
})
|
||||
llvmGlobal.AddMetadata(0, diglobal)
|
||||
}
|
||||
|
||||
+7
-7
@@ -14,7 +14,7 @@ import (
|
||||
// and returns the result as a single integer (the system call result). The
|
||||
// result is not further interpreted.
|
||||
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
num := b.getValue(call.Args[0])
|
||||
num := b.getValue(call.Args[0], getPos(call))
|
||||
switch {
|
||||
case b.GOARCH == "amd64" && b.GOOS == "linux":
|
||||
// Sources:
|
||||
@@ -37,7 +37,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{r12}",
|
||||
"{r13}",
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{edi}",
|
||||
"{ebp}",
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{r5}",
|
||||
"{r6}",
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{x4}",
|
||||
"{x5}",
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
@@ -177,12 +177,12 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
var paramTypes []llvm.Type
|
||||
var params []llvm.Value
|
||||
for _, val := range call.Args[2:] {
|
||||
param := b.getValue(val)
|
||||
param := b.getValue(val, getPos(call))
|
||||
params = append(params, param)
|
||||
paramTypes = append(paramTypes, param.Type())
|
||||
}
|
||||
llvmType := llvm.FunctionType(b.uintptrType, paramTypes, false)
|
||||
fn := b.getValue(call.Args[0])
|
||||
fn := b.getValue(call.Args[0], getPos(call))
|
||||
fnPtr := b.CreateIntToPtr(fn, llvm.PointerType(llvmType, 0), "")
|
||||
|
||||
// Prepare some functions that will be called later.
|
||||
|
||||
Vendored
+33
-31
@@ -10,32 +10,33 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.b = hidden global [2 x ptr] zeroinitializer, align 4
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = add i32 %x, %y
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -49,14 +50,14 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %5
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.divideByZeroPanic(ptr) #0
|
||||
declare void @runtime.divideByZeroPanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -66,12 +67,12 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -85,12 +86,12 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %5
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -100,66 +101,66 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp oeq float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp une float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp olt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp ole float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp oge float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret float %x.r
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret float %x.i
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fadd float %x.r, %y.r
|
||||
%1 = fadd float %x.i, %y.i
|
||||
@@ -169,7 +170,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fsub float %x.r, %y.r
|
||||
%1 = fsub float %x.i, %y.i
|
||||
@@ -179,7 +180,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fmul float %x.r, %y.r
|
||||
%1 = fmul float %x.i, %y.i
|
||||
@@ -193,27 +194,28 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%complit = alloca %main.kv.0, align 8
|
||||
%stackalloc = alloca i8, align 1
|
||||
store %main.kv.0 zeroinitializer, ptr %complit, align 8
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%b1 = alloca %main.kv.0, align 8
|
||||
%stackalloc = alloca i8, align 1
|
||||
store %main.kv.0 zeroinitializer, ptr %b1, align 8
|
||||
call void @runtime.trackPointer(ptr nonnull %b1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %b1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store %main.kv.0 %b, ptr %b1, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+24
-22
@@ -6,78 +6,79 @@ target triple = "wasm32-unknown-wasi"
|
||||
%runtime.channelBlockedList = type { ptr, ptr, ptr, { ptr, i32, i32 } }
|
||||
%runtime.chanSelectState = type { ptr, ptr }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
|
||||
store i32 3, ptr %chan.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #3
|
||||
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #0
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
|
||||
|
||||
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #3
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #0
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%complit = alloca {}, align 8
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #4
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #3
|
||||
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #3
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
||||
%select.send.value = alloca i32, align 4
|
||||
@@ -90,7 +91,7 @@ entry:
|
||||
store ptr %ch2, ptr %0, align 8
|
||||
%.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
|
||||
store ptr null, ptr %.repack3, align 4
|
||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #3
|
||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
|
||||
%1 = extractvalue { i32, i1 } %select.result, 0
|
||||
%2 = icmp eq i32 %1, 0
|
||||
@@ -107,9 +108,10 @@ select.body: ; preds = %select.next
|
||||
br label %select.done
|
||||
}
|
||||
|
||||
declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #0
|
||||
declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #1
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { argmemonly nocallback nofree nosync nounwind willreturn }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { argmemonly nocallback nofree nosync nounwind willreturn }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
+47
-33
@@ -7,6 +7,7 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
%runtime._defer = type { i32, ptr }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
@@ -15,7 +16,7 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.external(ptr) #0
|
||||
declare void @main.external(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
|
||||
@@ -25,20 +26,27 @@ entry:
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%0 = call ptr @llvm.stacksave()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #3
|
||||
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 { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
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) #4
|
||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
||||
br i1 %setjmp.result, label %1, label %lpad
|
||||
|
||||
1: ; preds = %entry
|
||||
call void @main.external(ptr undef) #3
|
||||
call void @main.external(ptr undef) #4
|
||||
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 = %1
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %3, %1
|
||||
rundefers.loophead: ; preds = %3, %rundefers.block
|
||||
%2 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %2, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
@@ -53,7 +61,7 @@ rundefers.loop: ; preds = %rundefers.loophead
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
%setjmp1 = 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) #4
|
||||
%setjmp1 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result2 = icmp eq i32 %setjmp1, 0
|
||||
br i1 %setjmp.result2, label %3, label %lpad
|
||||
|
||||
@@ -65,11 +73,10 @@ rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
|
||||
ret void
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end3
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
lpad: ; preds = %rundefers.callback012, %rundefers.callback0, %entry
|
||||
@@ -90,7 +97,7 @@ rundefers.loop5: ; preds = %rundefers.loophead6
|
||||
]
|
||||
|
||||
rundefers.callback012: ; preds = %rundefers.loop5
|
||||
%setjmp13 = 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) #4
|
||||
%setjmp13 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result14 = icmp eq i32 %setjmp13, 0
|
||||
br i1 %setjmp.result14, label %5, label %lpad
|
||||
|
||||
@@ -106,20 +113,20 @@ rundefers.end3: ; preds = %rundefers.loophead6
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
||||
declare ptr @llvm.stacksave() #2
|
||||
declare ptr @llvm.stacksave() #3
|
||||
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #0
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, ptr undef) #3
|
||||
call void @runtime.printint32(i32 3, ptr undef) #4
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #0
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #0
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
|
||||
@@ -130,7 +137,7 @@ entry:
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%0 = call ptr @llvm.stacksave()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #3
|
||||
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 { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
store ptr null, ptr %defer.alloca.repack22, align 4
|
||||
@@ -139,15 +146,22 @@ entry:
|
||||
%defer.alloca2.repack23 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca2, i32 0, i32 1
|
||||
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
|
||||
store ptr %defer.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) #4
|
||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
||||
br i1 %setjmp.result, label %1, label %lpad
|
||||
|
||||
1: ; preds = %entry
|
||||
call void @main.external(ptr undef) #3
|
||||
call void @main.external(ptr undef) #4
|
||||
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 = %1
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %4, %3, %1
|
||||
rundefers.loophead: ; preds = %4, %3, %rundefers.block
|
||||
%2 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %2, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
@@ -163,7 +177,7 @@ rundefers.loop: ; preds = %rundefers.loophead
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
%setjmp3 = 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) #4
|
||||
%setjmp3 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result4 = icmp eq i32 %setjmp3, 0
|
||||
br i1 %setjmp.result4, label %3, label %lpad
|
||||
|
||||
@@ -172,7 +186,7 @@ rundefers.callback0: ; preds = %rundefers.loop
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.callback1: ; preds = %rundefers.loop
|
||||
%setjmp5 = 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) #4
|
||||
%setjmp5 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result6 = icmp eq i32 %setjmp5, 0
|
||||
br i1 %setjmp.result6, label %4, label %lpad
|
||||
|
||||
@@ -184,11 +198,10 @@ rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
|
||||
ret void
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end7
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
lpad: ; preds = %rundefers.callback119, %rundefers.callback016, %rundefers.callback1, %rundefers.callback0, %entry
|
||||
@@ -210,7 +223,7 @@ rundefers.loop9: ; preds = %rundefers.loophead1
|
||||
]
|
||||
|
||||
rundefers.callback016: ; preds = %rundefers.loop9
|
||||
%setjmp17 = 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) #4
|
||||
%setjmp17 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result18 = icmp eq i32 %setjmp17, 0
|
||||
br i1 %setjmp.result18, label %6, label %lpad
|
||||
|
||||
@@ -219,7 +232,7 @@ rundefers.callback016: ; preds = %rundefers.loop9
|
||||
br label %rundefers.loophead10
|
||||
|
||||
rundefers.callback119: ; preds = %rundefers.loop9
|
||||
%setjmp20 = 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) #4
|
||||
%setjmp20 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result21 = icmp eq i32 %setjmp20, 0
|
||||
br i1 %setjmp.result21, label %7, label %lpad
|
||||
|
||||
@@ -237,19 +250,20 @@ rundefers.end7: ; preds = %rundefers.loophead1
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, ptr undef) #3
|
||||
call void @runtime.printint32(i32 3, ptr undef) #4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 5, ptr undef) #3
|
||||
call void @runtime.printint32(i32 5, ptr undef) #4
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { nocallback nofree nosync nounwind willreturn }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #4 = { nounwind returns_twice }
|
||||
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn }
|
||||
attributes #4 = { nounwind }
|
||||
attributes #5 = { nounwind returns_twice }
|
||||
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:wasmimport modulename empty
|
||||
func empty()
|
||||
|
||||
// ERROR: can only use //go:wasmimport on declarations
|
||||
//
|
||||
//go:wasmimport modulename implementation
|
||||
func implementation() {
|
||||
}
|
||||
|
||||
type Uint uint32
|
||||
|
||||
//go:wasmimport modulename validparam
|
||||
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
|
||||
//
|
||||
//go:wasmimport modulename invalidparam
|
||||
func invalidparam(a int, b string, c []byte, d *int32)
|
||||
|
||||
//go:wasmimport modulename validreturn
|
||||
func validreturn() int32
|
||||
|
||||
// ERROR: //go:wasmimport modulename manyreturns: too many return values
|
||||
//
|
||||
//go:wasmimport modulename manyreturns
|
||||
func manyreturns() (int32, int32)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn: unsupported result type int
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn
|
||||
func invalidreturn() int
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
|
||||
//
|
||||
//go:wasmimport modulename invalidUnsafePointerReturn
|
||||
func invalidUnsafePointerReturn() unsafe.Pointer
|
||||
Vendored
+14
-12
@@ -3,18 +3,19 @@ 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 triple = "wasm32-unknown-wasi"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -26,25 +27,25 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 {
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret float 0x41F0000000000000
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret i32 -1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 {
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = uitofp i32 %v to float
|
||||
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
||||
@@ -54,7 +55,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 {
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -67,7 +68,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 {
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 2.550000e+02
|
||||
@@ -79,7 +80,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 {
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%abovemin = fcmp oge float %v, -1.280000e+02
|
||||
%belowmax = fcmp ole float %v, 1.270000e+02
|
||||
@@ -92,5 +93,6 @@ entry:
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
|
||||
Vendored
+13
-11
@@ -3,46 +3,48 @@ 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 triple = "wasm32-unknown-wasi"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp eq ptr %callback.funcptr, null
|
||||
br i1 %0, label %fpcall.throw, label %fpcall.next
|
||||
|
||||
fpcall.next: ; preds = %entry
|
||||
call void %callback.funcptr(i32 3, ptr %callback.context) #2
|
||||
call void %callback.funcptr(i32 3, ptr %callback.context) #3
|
||||
ret void
|
||||
|
||||
fpcall.throw: ; preds = %entry
|
||||
call void @runtime.nilPanic(ptr undef) #2
|
||||
call void @runtime.nilPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.nilPanic(ptr) #0
|
||||
declare void @runtime.nilPanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+49
-47
@@ -21,98 +21,99 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 16, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new = call dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.scalar1, align 4
|
||||
%new1 = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new1 = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.scalar2, align 4
|
||||
%new2 = call ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new2 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.scalar3, align 4
|
||||
%new3 = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new3 = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.scalar4, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new = call dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.array1, align 4
|
||||
%new1 = call ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new1 = call dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.array2, align 4
|
||||
%new2 = call ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new2 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.array3, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new = call ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.struct1, align 4
|
||||
%new1 = call ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new1 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.struct2, align 4
|
||||
%new2 = call ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new2 = call dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.struct3, align 4
|
||||
%new3 = call ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new3 = call dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.struct4, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%new = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %new
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%makeslice = call 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 8
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 8
|
||||
%makeslice1 = call ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%makeslice1 = call 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 8
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 8
|
||||
%makeslice3 = call ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%makeslice3 = call 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 8
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 8
|
||||
@@ -120,20 +121,21 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call ptr @runtime.alloc(i32 16, ptr null, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%0 = call 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 { double, double }, ptr %0, i32 0, i32 1
|
||||
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) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret %runtime._interface %1
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+15
-13
@@ -5,26 +5,27 @@ target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %s.data
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp slt i16 %len, 0
|
||||
@@ -38,24 +39,25 @@ unsafe.String.next: ; preds = %entry
|
||||
%5 = zext i16 %len to i32
|
||||
%6 = insertvalue %runtime._string undef, ptr %ptr, 0
|
||||
%7 = insertvalue %runtime._string %6, i32 %5, 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret %runtime._string %7
|
||||
|
||||
unsafe.String.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #0
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %s.data
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
+42
-40
@@ -7,6 +7,7 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
@@ -18,30 +19,30 @@ entry:
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #8
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, ptr) #0
|
||||
declare void @main.regularFunction(i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #8
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #0
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #2
|
||||
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #8
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
|
||||
@@ -62,16 +63,16 @@ entry:
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%n = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #8
|
||||
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
store i32 3, ptr %n, align 4
|
||||
%0 = call ptr @runtime.alloc(i32 8, ptr null, ptr undef) #8
|
||||
%0 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %n, ptr %1, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #8
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
%2 = load i32, ptr %n, align 4
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #8
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
@@ -92,31 +93,31 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #0
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call ptr @runtime.alloc(i32 12, ptr null, ptr undef) #8
|
||||
%0 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
||||
store ptr %fn.funcptr, ptr %2, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #8
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #5 {
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
%4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #8
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -129,25 +130,25 @@ entry:
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #8
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #0
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #8
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #0
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call ptr @runtime.alloc(i32 16, ptr null, ptr undef) #8
|
||||
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr @"main$string", ptr %1, align 4
|
||||
@@ -155,15 +156,15 @@ entry:
|
||||
store i32 4, ptr %.repack1, align 4
|
||||
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
||||
store ptr %itf.typecode, ptr %2, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #8
|
||||
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) #8
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #6
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #7 {
|
||||
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 { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
|
||||
@@ -172,16 +173,17 @@ entry:
|
||||
%5 = load i32, ptr %4, align 4
|
||||
%6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
|
||||
%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) #8
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
|
||||
attributes #6 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #7 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #8 = { nounwind }
|
||||
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
|
||||
+61
-59
@@ -7,158 +7,159 @@ target triple = "wasm32-unknown-wasi"
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, ptr) #0
|
||||
declare void @main.regularFunction(i32, ptr) #1
|
||||
|
||||
declare void @runtime.deadlock(ptr) #0
|
||||
declare void @runtime.deadlock(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #8
|
||||
call void @runtime.deadlock(ptr undef) #8
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
|
||||
call void @runtime.deadlock(ptr undef) #8
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%n = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #8
|
||||
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 3, ptr %n, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #8
|
||||
%0 = call ptr @runtime.alloc(i32 8, ptr null, ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
|
||||
%0 = call 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 { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
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 16384, ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 16384, ptr undef) #9
|
||||
%2 = load i32, ptr %n, align 4
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #8
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
store i32 7, ptr %context, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
|
||||
call void @runtime.deadlock(ptr undef) #8
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #0
|
||||
declare void @runtime.printint32(i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call ptr @runtime.alloc(i32 12, ptr null, ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
|
||||
%0 = call 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 { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
||||
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 16384, ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 16384, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #5 {
|
||||
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
|
||||
entry:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
%4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #8
|
||||
call void @runtime.deadlock(ptr undef) #8
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #8
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #0
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #8
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #0
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call ptr @runtime.alloc(i32 16, ptr null, ptr undef) #8
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
|
||||
%0 = call 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 { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr @"main$string", ptr %1, align 4
|
||||
@@ -166,14 +167,14 @@ entry:
|
||||
store i32 4, ptr %.repack1, align 4
|
||||
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
||||
store ptr %itf.typecode, ptr %2, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 16384, ptr undef) #8
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 16384, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #6
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #7 {
|
||||
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 { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
|
||||
@@ -182,17 +183,18 @@ entry:
|
||||
%5 = load i32, ptr %4, align 4
|
||||
%6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
|
||||
%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) #8
|
||||
call void @runtime.deadlock(ptr undef) #8
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #7 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #8 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
|
||||
Vendored
+48
-45
@@ -6,66 +6,68 @@ target triple = "wasm32-unknown-wasi"
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.typeid:basic:int" = external constant i8
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #6
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
|
||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -75,12 +77,12 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #0
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -90,12 +92,12 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #2
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -105,33 +107,34 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #6
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #4
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #6
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
|
||||
%1 = extractvalue %runtime._string %0, 0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #6
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
|
||||
ret %runtime._string %0
|
||||
}
|
||||
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #5
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #6 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #7 = { nounwind }
|
||||
|
||||
Vendored
-15
@@ -24,18 +24,3 @@ func pointerCastToUnsafe(x *int) unsafe.Pointer {
|
||||
func pointerCastToUnsafeNoop(x *byte) unsafe.Pointer {
|
||||
return unsafe.Pointer(x)
|
||||
}
|
||||
|
||||
// The compiler has support for a few special cast+add patterns that are
|
||||
// transformed into a single GEP.
|
||||
|
||||
func pointerUnsafeGEPFixedOffset(ptr *byte) *byte {
|
||||
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + 10))
|
||||
}
|
||||
|
||||
func pointerUnsafeGEPByteOffset(ptr *byte, offset uintptr) *byte {
|
||||
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset))
|
||||
}
|
||||
|
||||
func pointerUnsafeGEPIntOffset(ptr *int32, offset uintptr) *int32 {
|
||||
return (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset*4))
|
||||
}
|
||||
|
||||
Vendored
+14
-46
@@ -3,80 +3,48 @@ 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 triple = "wasm32-unknown-wasi"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret [0 x i32] zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerUnsafeGEPFixedOffset(ptr dereferenceable_or_null(1) %ptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%0 = getelementptr inbounds i8, ptr %ptr, i32 10
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerUnsafeGEPByteOffset(ptr dereferenceable_or_null(1) %ptr, i32 %offset, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%0 = getelementptr inbounds i8, ptr %ptr, i32 %offset
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerUnsafeGEPIntOffset(ptr dereferenceable_or_null(4) %ptr, i32 %offset, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%0 = shl i32 %offset, 2
|
||||
%1 = getelementptr inbounds i8, ptr %ptr, i32 %0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %1
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+3
@@ -59,6 +59,9 @@ func functionInSection() {
|
||||
func exportedFunctionInSection() {
|
||||
}
|
||||
|
||||
//go:wasmimport modulename import1
|
||||
func declaredImport()
|
||||
|
||||
// This function should not: it's only a declaration and not a definition.
|
||||
//
|
||||
//go:section .special_function_section
|
||||
|
||||
Vendored
+23
-18
@@ -11,59 +11,64 @@ target triple = "wasm32-unknown-wasi"
|
||||
@undefinedGlobalNotInSection = external global i32, align 4
|
||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @extern_func() #2 {
|
||||
define void @extern_func() #3 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @somepkg.someFunction2(ptr) #0
|
||||
declare void @somepkg.someFunction2(ptr) #1
|
||||
|
||||
; Function Attrs: inlinehint nounwind
|
||||
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #3 {
|
||||
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #4 {
|
||||
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #5 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #1 section ".special_function_section" {
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @exportedFunctionInSection() #5 section ".special_function_section" {
|
||||
; Function Attrs: noinline nounwind
|
||||
define void @exportedFunctionInSection() #6 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #0
|
||||
declare void @main.declaredImport() #7
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
||||
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
|
||||
Vendored
+64
-62
@@ -3,30 +3,31 @@ 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 triple = "wasm32-unknown-wasi"
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret i32 %ints.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret i32 %ints.cap
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %ints.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -37,84 +38,84 @@ lookup.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #2
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #0
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%varargs = call ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%varargs = call 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 [3 x i32], ptr %varargs, i32 0, i32 1
|
||||
store i32 2, ptr %0, align 4
|
||||
%1 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 2
|
||||
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) #2
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
|
||||
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
|
||||
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
|
||||
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
|
||||
%2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
|
||||
%3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1
|
||||
%4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %4
|
||||
}
|
||||
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #0
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #2
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
|
||||
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
|
||||
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
|
||||
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #2
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
|
||||
ret i32 %copy.n
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #0
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #2
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.slicePanic(ptr) #0
|
||||
declare void @runtime.slicePanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
@@ -122,20 +123,20 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 1
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #2
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
||||
@@ -143,20 +144,20 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = mul i32 %len, 3
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #2
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
||||
@@ -164,39 +165,39 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #2
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = getelementptr i8, ptr %p, i32 %len
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = trunc i64 %len to i32
|
||||
%1 = getelementptr i8, ptr %p, i32 %0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = icmp ult i32 %s.len, 4
|
||||
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
||||
@@ -205,18 +206,18 @@ slicetoarray.next: ; preds = %entry
|
||||
ret ptr %s.data
|
||||
|
||||
slicetoarray.throw: ; preds = %entry
|
||||
call void @runtime.sliceToArrayPointerPanic(ptr undef) #2
|
||||
call void @runtime.sliceToArrayPointerPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #0
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 {
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #2
|
||||
%makeslice = call dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
slicetoarray.next: ; preds = %entry
|
||||
@@ -227,7 +228,7 @@ slicetoarray.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i32 %len, 1073741823
|
||||
@@ -241,18 +242,18 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %7
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #0
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp eq ptr %ptr, null
|
||||
@@ -265,16 +266,16 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1
|
||||
%6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %6
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -289,16 +290,16 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -313,14 +314,15 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+23
-21
@@ -7,36 +7,37 @@ target triple = "wasm32-unknown-wasi"
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret %runtime._string { ptr @"main$string", i32 3 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 {
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret %runtime._string zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret i32 %s.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -47,40 +48,40 @@ lookup.next: ; preds = %entry
|
||||
ret i8 %1
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #2
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #0
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #0
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, 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 #1 {
|
||||
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
%1 = xor i1 %0, true
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #2
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #0
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 {
|
||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = zext i8 %x to i32
|
||||
%.not = icmp ult i32 %0, %s.len
|
||||
@@ -92,10 +93,11 @@ lookup.next: ; preds = %entry
|
||||
ret i8 %2
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #2
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+39
-37
@@ -5,18 +5,19 @@ target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%main.hasPadding = type { i1, i32, i1 }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -26,16 +27,16 @@ entry:
|
||||
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
|
||||
%stackalloc = alloca i8, align 1
|
||||
store %main.hasPadding zeroinitializer, ptr %s, align 8
|
||||
call void @runtime.trackPointer(ptr nonnull %s, ptr nonnull %stackalloc, ptr undef) #4
|
||||
call void @runtime.trackPointer(ptr nonnull %s, ptr nonnull %stackalloc, ptr undef) #5
|
||||
store %main.hasPadding %2, ptr %s, align 8
|
||||
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 8
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #4
|
||||
%5 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
|
||||
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)
|
||||
%6 = load i32, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
@@ -43,17 +44,17 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4
|
||||
|
||||
declare void @runtime.memzero(ptr, i32, ptr) #0
|
||||
declare void @runtime.memzero(ptr, i32, ptr) #1
|
||||
|
||||
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #0
|
||||
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1
|
||||
|
||||
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -63,26 +64,26 @@ entry:
|
||||
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
|
||||
%stackalloc = alloca i8, align 1
|
||||
store %main.hasPadding zeroinitializer, ptr %s, align 8
|
||||
call void @runtime.trackPointer(ptr nonnull %s, ptr nonnull %stackalloc, ptr undef) #4
|
||||
call void @runtime.trackPointer(ptr nonnull %s, ptr nonnull %stackalloc, ptr undef) #5
|
||||
store %main.hasPadding %2, ptr %s, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
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 8
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #4
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
|
||||
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #0
|
||||
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -91,7 +92,7 @@ entry:
|
||||
store %main.hasPadding zeroinitializer, ptr %s1, align 8
|
||||
%s1.repack2 = getelementptr inbounds [2 x %main.hasPadding], ptr %s1, i32 0, i32 1
|
||||
store %main.hasPadding zeroinitializer, ptr %s1.repack2, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %s1, ptr nonnull %stackalloc, ptr undef) #4
|
||||
call void @runtime.trackPointer(ptr nonnull %s1, ptr nonnull %stackalloc, ptr undef) #5
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %s1, align 8
|
||||
%s1.repack3 = getelementptr inbounds [2 x %main.hasPadding], ptr %s1, i32 0, i32 1
|
||||
@@ -105,14 +106,14 @@ entry:
|
||||
%s.elt9 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt9, ptr %hashmap.key.repack8, align 4
|
||||
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #4
|
||||
%4 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
|
||||
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)
|
||||
%5 = load i32, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
@@ -120,7 +121,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -129,7 +130,7 @@ entry:
|
||||
store %main.hasPadding zeroinitializer, ptr %s1, align 8
|
||||
%s1.repack2 = getelementptr inbounds [2 x %main.hasPadding], ptr %s1, i32 0, i32 1
|
||||
store %main.hasPadding zeroinitializer, ptr %s1.repack2, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %s1, ptr nonnull %stackalloc, ptr undef) #4
|
||||
call void @runtime.trackPointer(ptr nonnull %s1, ptr nonnull %stackalloc, ptr undef) #5
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %s1, align 8
|
||||
%s1.repack3 = getelementptr inbounds [2 x %main.hasPadding], ptr %s1, i32 0, i32 1
|
||||
@@ -144,27 +145,28 @@ entry:
|
||||
%s.elt9 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt9, ptr %hashmap.key.repack8, align 4
|
||||
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #4
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { argmemonly nocallback nofree nosync nounwind willreturn }
|
||||
attributes #4 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { argmemonly nocallback nofree nosync nounwind willreturn }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
@@ -9,7 +9,7 @@ import "go/types"
|
||||
// runtime/volatile.LoadT().
|
||||
func (b *builder) createVolatileLoad() {
|
||||
b.createFunctionStart(true)
|
||||
addr := b.getValue(b.fn.Params[0])
|
||||
addr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
b.createNilCheck(b.fn.Params[0], addr, "deref")
|
||||
valType := b.getLLVMType(b.fn.Params[0].Type().(*types.Pointer).Elem())
|
||||
val := b.CreateLoad(valType, addr, "")
|
||||
@@ -21,8 +21,8 @@ func (b *builder) createVolatileLoad() {
|
||||
// runtime/volatile.StoreT().
|
||||
func (b *builder) createVolatileStore() {
|
||||
b.createFunctionStart(true)
|
||||
addr := b.getValue(b.fn.Params[0])
|
||||
val := b.getValue(b.fn.Params[1])
|
||||
addr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
b.createNilCheck(b.fn.Params[0], addr, "deref")
|
||||
store := b.CreateStore(val, addr)
|
||||
store.SetVolatile(true)
|
||||
|
||||
+2
-1
@@ -115,8 +115,9 @@ func TestCorpus(t *testing.T) {
|
||||
var tags buildutil.TagsFlag
|
||||
tags.Set(repo.Tags)
|
||||
opts.Tags = []string(tags)
|
||||
opts.TestConfig.Verbose = testing.Verbose()
|
||||
|
||||
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", false, "")
|
||||
passed, err := Test(path, out, out, &opts, "")
|
||||
if err != nil {
|
||||
t.Errorf("test error: %v", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ require (
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
go.bug.st/serial v1.3.5
|
||||
golang.org/x/sys v0.4.0
|
||||
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8
|
||||
|
||||
@@ -43,6 +43,8 @@ github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3px
|
||||
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/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
go.bug.st/serial v1.3.5 h1:k50SqGZCnHZ2MiBQgzccXWG+kd/XpOs1jUljpDDKzaE=
|
||||
go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.28.0-dev"
|
||||
const Version = "0.28.1"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ object. Every memory object is given an index, and pointers use that index to
|
||||
look up the current active object for the pointer to load from or to copy
|
||||
when storing to it.
|
||||
|
||||
Rolling back a function should roll back everyting, including the few
|
||||
Rolling back a function should roll back everything, including the few
|
||||
instructions emitted at runtime. This is done by treating instructions much
|
||||
like memory objects and removing the created instructions when necessary.
|
||||
|
||||
@@ -88,7 +88,7 @@ LLVM than initialization code. Also, there are a few other benefits:
|
||||
they can be propagated and provide some opportunities for other
|
||||
optimizations (like dead code elimination when branching on the contents of
|
||||
a global).
|
||||
* Constants are much more efficent on microcontrollers, as they can be
|
||||
* Constants are much more efficient on microcontrollers, as they can be
|
||||
allocated in flash instead of RAM.
|
||||
|
||||
The Go SSA package does not create constant initializers for globals.
|
||||
|
||||
+1
-1
@@ -254,7 +254,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
|
||||
}
|
||||
}
|
||||
case llvm.BitCast, llvm.IntToPtr, llvm.PtrToInt:
|
||||
// Bitcasts are ususally used to cast a pointer from one type to
|
||||
// Bitcasts are usually used to cast a pointer from one type to
|
||||
// another leaving the pointer itself intact.
|
||||
inst.name = llvmInst.Name()
|
||||
inst.operands = []value{
|
||||
|
||||
+20
-57
@@ -346,16 +346,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
dstObj.buffer = dstBuf
|
||||
mem.put(dst.index(), dstObj)
|
||||
}
|
||||
switch inst.llvmInst.Type().IntTypeWidth() {
|
||||
case 16:
|
||||
locals[inst.localIndex] = literalValue{uint16(n)}
|
||||
case 32:
|
||||
locals[inst.localIndex] = literalValue{uint32(n)}
|
||||
case 64:
|
||||
locals[inst.localIndex] = literalValue{uint64(n)}
|
||||
default:
|
||||
panic("unknown integer type width")
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(n, inst.llvmInst.Type().IntTypeWidth())
|
||||
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
|
||||
// Copy a block of memory from one pointer to another.
|
||||
dst, err := operands[1].asPointer(r)
|
||||
@@ -647,16 +638,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||
ptrValue := operands[0].Uint() + offset
|
||||
switch operands[0].len(r) {
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{uint64(ptrValue)}
|
||||
case 4:
|
||||
locals[inst.localIndex] = literalValue{uint32(ptrValue)}
|
||||
case 2:
|
||||
locals[inst.localIndex] = literalValue{uint16(ptrValue)}
|
||||
default:
|
||||
panic("pointer operand is not of a known pointer size")
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||
continue
|
||||
}
|
||||
ptr = ptr.addOffset(int64(offset))
|
||||
@@ -754,30 +736,33 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err == nil {
|
||||
// The lhs is a pointer. This sometimes happens for particular
|
||||
// pointer tricks.
|
||||
switch inst.opcode {
|
||||
case llvm.Add:
|
||||
if inst.opcode == llvm.Add {
|
||||
// This likely means this is part of a
|
||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||
locals[inst.localIndex] = lhsPtr
|
||||
continue
|
||||
case llvm.Xor:
|
||||
if rhs.Uint() == 0 {
|
||||
// Special workaround for strings.noescape, see
|
||||
// src/strings/builder.go in the Go source tree. This is
|
||||
// the identity operator, so we can return the input.
|
||||
locals[inst.localIndex] = lhs
|
||||
continue
|
||||
}
|
||||
default:
|
||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
||||
// Special workaround for strings.noescape, see
|
||||
// src/strings/builder.go in the Go source tree. This is
|
||||
// the identity operator, so we can return the input.
|
||||
locals[inst.localIndex] = lhs
|
||||
} else if inst.opcode == llvm.And && rhs.Uint() < 8 {
|
||||
// This is probably part of a pattern to get the lower bits
|
||||
// of a pointer for pointer tagging, like this:
|
||||
// uintptr(unsafe.Pointer(t)) & 0b11
|
||||
// We can actually support this easily by ANDing with the
|
||||
// pointer offset.
|
||||
result := uint64(lhsPtr.offset()) & rhs.Uint()
|
||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||
} else {
|
||||
// Catch-all for weird operations that should just be done
|
||||
// at runtime.
|
||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||
if err != nil {
|
||||
return nil, mem, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
var result uint64
|
||||
switch inst.opcode {
|
||||
@@ -810,18 +795,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
switch lhs.len(r) {
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{result}
|
||||
case 4:
|
||||
locals[inst.localIndex] = literalValue{uint32(result)}
|
||||
case 2:
|
||||
locals[inst.localIndex] = literalValue{uint16(result)}
|
||||
case 1:
|
||||
locals[inst.localIndex] = literalValue{uint8(result)}
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", lhs, rhs, "->", result)
|
||||
}
|
||||
@@ -843,18 +817,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
||||
}
|
||||
switch bitwidth {
|
||||
case 64:
|
||||
locals[inst.localIndex] = literalValue{value}
|
||||
case 32:
|
||||
locals[inst.localIndex] = literalValue{uint32(value)}
|
||||
case 16:
|
||||
locals[inst.localIndex] = literalValue{uint16(value)}
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{uint8(value)}
|
||||
default:
|
||||
panic("unknown integer size in sext/zext/trunc")
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(value, int(bitwidth))
|
||||
case llvm.SIToFP, llvm.UIToFP:
|
||||
var value float64
|
||||
switch inst.opcode {
|
||||
|
||||
+17
-1
@@ -12,7 +12,7 @@ package interp
|
||||
// done in interp and results in a revert.
|
||||
//
|
||||
// Right now the memory is assumed to be little endian. This will need an update
|
||||
// for big endian arcitectures, if TinyGo ever adds support for one.
|
||||
// for big endian architectures, if TinyGo ever adds support for one.
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@@ -373,6 +373,22 @@ type literalValue struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// Make a literalValue given the number of bits.
|
||||
func makeLiteralInt(value uint64, bits int) literalValue {
|
||||
switch bits {
|
||||
case 64:
|
||||
return literalValue{value}
|
||||
case 32:
|
||||
return literalValue{uint32(value)}
|
||||
case 16:
|
||||
return literalValue{uint16(value)}
|
||||
case 8:
|
||||
return literalValue{uint8(value)}
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
}
|
||||
|
||||
func (v literalValue) len(r *runner) uint32 {
|
||||
switch v.value.(type) {
|
||||
case uint64:
|
||||
|
||||
Vendored
+28
-28
@@ -2,17 +2,17 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32--wasi"
|
||||
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@pointerFree12 = global i8* null
|
||||
@pointerFree7 = global i8* null
|
||||
@pointerFree3 = global i8* null
|
||||
@pointerFree0 = global i8* null
|
||||
@layout1 = global i8* null
|
||||
@layout2 = global i8* null
|
||||
@layout3 = global i8* null
|
||||
@layout4 = global i8* null
|
||||
@bigobj1 = global i8* null
|
||||
@pointerFree12 = global ptr null
|
||||
@pointerFree7 = global ptr null
|
||||
@pointerFree3 = global ptr null
|
||||
@pointerFree0 = global ptr null
|
||||
@layout1 = global ptr null
|
||||
@layout2 = global ptr null
|
||||
@layout3 = global ptr null
|
||||
@layout4 = global ptr null
|
||||
@bigobj1 = global ptr null
|
||||
|
||||
declare i8* @runtime.alloc(i32, i8*) unnamed_addr
|
||||
declare ptr @runtime.alloc(i32, ptr) unnamed_addr
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
call void @main.init()
|
||||
@@ -21,33 +21,33 @@ define void @runtime.initAll() unnamed_addr {
|
||||
|
||||
define internal void @main.init() unnamed_addr {
|
||||
; Object that's word-aligned.
|
||||
%pointerFree12 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree12, i8** @pointerFree12
|
||||
%pointerFree12 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree12, ptr @pointerFree12
|
||||
; Object larger than a word but not word-aligned.
|
||||
%pointerFree7 = call i8* @runtime.alloc(i32 7, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree7, i8** @pointerFree7
|
||||
%pointerFree7 = call ptr @runtime.alloc(i32 7, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree7, ptr @pointerFree7
|
||||
; Object smaller than a word (and of course not word-aligned).
|
||||
%pointerFree3 = call i8* @runtime.alloc(i32 3, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree3, i8** @pointerFree3
|
||||
%pointerFree3 = call ptr @runtime.alloc(i32 3, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree3, ptr @pointerFree3
|
||||
; Zero-sized object.
|
||||
%pointerFree0 = call i8* @runtime.alloc(i32 0, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree0, i8** @pointerFree0
|
||||
%pointerFree0 = call ptr @runtime.alloc(i32 0, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree0, ptr @pointerFree0
|
||||
|
||||
; Object made out of 3 pointers.
|
||||
%layout1 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 67 to i8*))
|
||||
store i8* %layout1, i8** @layout1
|
||||
%layout1 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 67 to ptr))
|
||||
store ptr %layout1, ptr @layout1
|
||||
; Array (or slice) of 5 slices.
|
||||
%layout2 = call i8* @runtime.alloc(i32 60, i8* inttoptr (i32 71 to i8*))
|
||||
store i8* %layout2, i8** @layout2
|
||||
%layout2 = call ptr @runtime.alloc(i32 60, ptr inttoptr (i32 71 to ptr))
|
||||
store ptr %layout2, ptr @layout2
|
||||
; Oddly shaped object, using all bits in the layout integer.
|
||||
%layout3 = call i8* @runtime.alloc(i32 104, i8* inttoptr (i32 2467830261 to i8*))
|
||||
store i8* %layout3, i8** @layout3
|
||||
%layout3 = call ptr @runtime.alloc(i32 104, ptr inttoptr (i32 2467830261 to ptr))
|
||||
store ptr %layout3, ptr @layout3
|
||||
; ...repeated.
|
||||
%layout4 = call i8* @runtime.alloc(i32 312, i8* inttoptr (i32 2467830261 to i8*))
|
||||
store i8* %layout4, i8** @layout4
|
||||
%layout4 = call ptr @runtime.alloc(i32 312, ptr inttoptr (i32 2467830261 to ptr))
|
||||
store ptr %layout4, ptr @layout4
|
||||
|
||||
; Large object that needs to be stored in a separate global.
|
||||
%bigobj1 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*))
|
||||
store i8* %bigobj1, i8** @bigobj1
|
||||
%bigobj1 = call ptr @runtime.alloc(i32 248, ptr @"runtime/gc.layout:62-2000000000000001")
|
||||
store ptr %bigobj1, ptr @bigobj1
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+14
-14
@@ -1,24 +1,24 @@
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32--wasi"
|
||||
|
||||
@pointerFree12 = local_unnamed_addr global i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"main$alloc", i32 0, i32 0)
|
||||
@pointerFree7 = local_unnamed_addr global i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"main$alloc.1", i32 0, i32 0)
|
||||
@pointerFree3 = local_unnamed_addr global i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$alloc.2", i32 0, i32 0)
|
||||
@pointerFree0 = local_unnamed_addr global i8* getelementptr inbounds ([0 x i8], [0 x i8]* @"main$alloc.3", i32 0, i32 0)
|
||||
@layout1 = local_unnamed_addr global i8* bitcast ([3 x i8*]* @"main$alloc.4" to i8*)
|
||||
@layout2 = local_unnamed_addr global i8* bitcast ([5 x { i8*, i32, i32 }]* @"main$alloc.5" to i8*)
|
||||
@layout3 = local_unnamed_addr global i8* bitcast ({ i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }* @"main$alloc.6" to i8*)
|
||||
@layout4 = local_unnamed_addr global i8* bitcast ([3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }]* @"main$alloc.7" to i8*)
|
||||
@bigobj1 = local_unnamed_addr global i8* bitcast ({ i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* }* @"main$alloc.8" to i8*)
|
||||
@pointerFree12 = local_unnamed_addr global ptr @"main$alloc"
|
||||
@pointerFree7 = local_unnamed_addr global ptr @"main$alloc.1"
|
||||
@pointerFree3 = local_unnamed_addr global ptr @"main$alloc.2"
|
||||
@pointerFree0 = local_unnamed_addr global ptr @"main$alloc.3"
|
||||
@layout1 = local_unnamed_addr global ptr @"main$alloc.4"
|
||||
@layout2 = local_unnamed_addr global ptr @"main$alloc.5"
|
||||
@layout3 = local_unnamed_addr global ptr @"main$alloc.6"
|
||||
@layout4 = local_unnamed_addr global ptr @"main$alloc.7"
|
||||
@bigobj1 = local_unnamed_addr global ptr @"main$alloc.8"
|
||||
@"main$alloc" = internal global [12 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.1" = internal global [7 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.2" = internal global [3 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.3" = internal global [0 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.4" = internal global [3 x i8*] zeroinitializer, align 4
|
||||
@"main$alloc.5" = internal global [5 x { i8*, i32, i32 }] zeroinitializer, align 4
|
||||
@"main$alloc.6" = internal global { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* } zeroinitializer, align 4
|
||||
@"main$alloc.7" = internal global [3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }] zeroinitializer, align 4
|
||||
@"main$alloc.8" = internal global { i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* } zeroinitializer, align 4
|
||||
@"main$alloc.4" = internal global [3 x ptr] zeroinitializer, align 4
|
||||
@"main$alloc.5" = internal global [5 x { ptr, i32, i32 }] zeroinitializer, align 4
|
||||
@"main$alloc.6" = internal global { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr } zeroinitializer, align 4
|
||||
@"main$alloc.7" = internal global [3 x { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr }] zeroinitializer, align 4
|
||||
@"main$alloc.8" = internal global { ptr, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, ptr } zeroinitializer, align 4
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
ret void
|
||||
|
||||
Vendored
+21
-21
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
|
||||
@main.nonConst1 = global [4 x i64] zeroinitializer
|
||||
@main.nonConst2 = global i64 0
|
||||
@main.someArray = global [8 x {i16, i32}] zeroinitializer
|
||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
|
||||
@main.exportedConst = constant i64 42
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = global i16 0
|
||||
@@ -24,7 +24,7 @@ entry:
|
||||
|
||||
define void @main() unnamed_addr {
|
||||
entry:
|
||||
%0 = load i64, i64* @main.v1
|
||||
%0 = load i64, ptr @main.v1
|
||||
call void @runtime.printint64(i64 %0)
|
||||
call void @runtime.printnl()
|
||||
ret void
|
||||
@@ -37,43 +37,43 @@ entry:
|
||||
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
store i64 3, i64* @main.v1
|
||||
store i64 3, ptr @main.v1
|
||||
call void @"main.init#1"()
|
||||
|
||||
; test the following pattern:
|
||||
; func someValue() int // extern function
|
||||
; var nonConst1 = [4]int{someValue(), 0, 0, 0}
|
||||
%value1 = call i64 @someValue()
|
||||
%gep1 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
||||
store i64 %value1, i64* %gep1
|
||||
%gep1 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
|
||||
store i64 %value1, ptr %gep1
|
||||
|
||||
; Test that the global really is marked dirty:
|
||||
; var nonConst2 = nonConst1[0]
|
||||
%gep2 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
||||
%value2 = load i64, i64* %gep2
|
||||
store i64 %value2, i64* @main.nonConst2
|
||||
%gep2 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
|
||||
%value2 = load i64, ptr %gep2
|
||||
store i64 %value2, ptr @main.nonConst2
|
||||
|
||||
; Test that the following GEP works:
|
||||
; var someArray
|
||||
; modifyExternal(&someArray[3].field1)
|
||||
%gep3 = getelementptr [8 x {i16, i32}], [8 x {i16, i32}]* @main.someArray, i32 0, i32 3, i32 1
|
||||
call void @modifyExternal(i32* %gep3)
|
||||
%gep3 = getelementptr [8 x {i16, i32}], ptr @main.someArray, i32 0, i32 3, i32 1
|
||||
call void @modifyExternal(ptr %gep3)
|
||||
|
||||
; Test that marking a value as external also marks all referenced values.
|
||||
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
|
||||
store i16 5, i16* @main.exposedValue1
|
||||
call void @modifyExternal(ptr @main.exportedValue)
|
||||
store i16 5, ptr @main.exposedValue1
|
||||
|
||||
; Test that marking a constant as external still allows loading from it.
|
||||
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
|
||||
%constLoad = load i64, i64 * @main.exportedConst
|
||||
call void @readExternal(ptr @main.exportedConst)
|
||||
%constLoad = load i64, ptr @main.exportedConst
|
||||
call void @runtime.printint64(i64 %constLoad)
|
||||
|
||||
; Test that this even propagates through functions.
|
||||
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
|
||||
store i16 7, i16* @main.exposedValue2
|
||||
call void @modifyExternal(ptr @willModifyGlobal)
|
||||
store i16 7, ptr @main.exposedValue2
|
||||
|
||||
; Test that inline assembly is ignored.
|
||||
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
|
||||
call void @modifyExternal(ptr @hasInlineAsm)
|
||||
|
||||
; Test switch statement.
|
||||
%switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6
|
||||
@@ -86,7 +86,7 @@ entry:
|
||||
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
|
||||
call void @runtime.printint64(i64 %elt)
|
||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
||||
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
|
||||
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
||||
|
||||
ret void
|
||||
}
|
||||
@@ -100,16 +100,16 @@ entry:
|
||||
|
||||
declare i64 @someValue()
|
||||
|
||||
declare void @modifyExternal(i32*)
|
||||
declare void @modifyExternal(ptr)
|
||||
|
||||
declare void @readExternal(i32*)
|
||||
declare void @readExternal(ptr)
|
||||
|
||||
; This function will modify an external value. By passing this function as a
|
||||
; function pointer to an external function, @main.exposedValue2 should be
|
||||
; marked as external.
|
||||
define void @willModifyGlobal() {
|
||||
entry:
|
||||
store i16 8, i16* @main.exposedValue2
|
||||
store i16 8, ptr @main.exposedValue2
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+15
-15
@@ -4,7 +4,7 @@ target triple = "x86_64--linux"
|
||||
@main.nonConst1 = local_unnamed_addr global [4 x i64] zeroinitializer
|
||||
@main.nonConst2 = local_unnamed_addr global i64 0
|
||||
@main.someArray = global [8 x { i16, i32 }] zeroinitializer
|
||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
|
||||
@main.exportedConst = constant i64 42
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||
@@ -19,17 +19,17 @@ entry:
|
||||
call void @runtime.printint64(i64 5)
|
||||
call void @runtime.printnl()
|
||||
%value1 = call i64 @someValue()
|
||||
store i64 %value1, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
|
||||
%value2 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
|
||||
store i64 %value2, i64* @main.nonConst2, align 8
|
||||
call void @modifyExternal(i32* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ([8 x { i16, i32 }]* @main.someArray to i8*), i32 28) to i32*))
|
||||
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
|
||||
store i16 5, i16* @main.exposedValue1, align 2
|
||||
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
|
||||
store i64 %value1, ptr @main.nonConst1, align 8
|
||||
%value2 = load i64, ptr @main.nonConst1, align 8
|
||||
store i64 %value2, ptr @main.nonConst2, align 8
|
||||
call void @modifyExternal(ptr getelementptr inbounds (i8, ptr @main.someArray, i32 28))
|
||||
call void @modifyExternal(ptr @main.exportedValue)
|
||||
store i16 5, ptr @main.exposedValue1, align 2
|
||||
call void @readExternal(ptr @main.exportedConst)
|
||||
call void @runtime.printint64(i64 42)
|
||||
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
|
||||
store i16 7, i16* @main.exposedValue2, align 2
|
||||
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
|
||||
call void @modifyExternal(ptr @willModifyGlobal)
|
||||
store i16 7, ptr @main.exposedValue2, align 2
|
||||
call void @modifyExternal(ptr @hasInlineAsm)
|
||||
call void @runtime.printint64(i64 6)
|
||||
call void @runtime.printint64(i64 -1)
|
||||
%agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct()
|
||||
@@ -42,7 +42,7 @@ entry:
|
||||
%agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0
|
||||
%agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1
|
||||
%agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2
|
||||
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue, align 8
|
||||
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, ptr @main.insertedValue, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ entry:
|
||||
|
||||
declare i64 @someValue() local_unnamed_addr
|
||||
|
||||
declare void @modifyExternal(i32*) local_unnamed_addr
|
||||
declare void @modifyExternal(ptr) local_unnamed_addr
|
||||
|
||||
declare void @readExternal(i32*) local_unnamed_addr
|
||||
declare void @readExternal(ptr) local_unnamed_addr
|
||||
|
||||
define void @willModifyGlobal() {
|
||||
entry:
|
||||
store i16 8, i16* @main.exposedValue2, align 2
|
||||
store i16 8, ptr @main.exposedValue2, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+19
-11
@@ -4,8 +4,9 @@ target triple = "x86_64--linux"
|
||||
@intToPtrResult = global i8 0
|
||||
@ptrToIntResult = global i8 0
|
||||
@icmpResult = global i8 0
|
||||
@pointerTagResult = global i64 0
|
||||
@someArray = internal global {i16, i8, i8} zeroinitializer
|
||||
@someArrayPointer = global i8* zeroinitializer
|
||||
@someArrayPointer = global ptr zeroinitializer
|
||||
|
||||
define void @runtime.initAll() {
|
||||
call void @main.init()
|
||||
@@ -17,49 +18,56 @@ define internal void @main.init() {
|
||||
call void @testPtrToInt()
|
||||
call void @testConstGEP()
|
||||
call void @testICmp()
|
||||
call void @testPointerTag()
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testIntToPtr() {
|
||||
%nil = icmp eq i8* inttoptr (i64 1024 to i8*), null
|
||||
%nil = icmp eq ptr inttoptr (i64 1024 to ptr), null
|
||||
br i1 %nil, label %a, label %b
|
||||
a:
|
||||
; should not be reached
|
||||
store i8 1, i8* @intToPtrResult
|
||||
store i8 1, ptr @intToPtrResult
|
||||
ret void
|
||||
b:
|
||||
; should be reached
|
||||
store i8 2, i8* @intToPtrResult
|
||||
store i8 2, ptr @intToPtrResult
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testPtrToInt() {
|
||||
%zero = icmp eq i64 ptrtoint (i8* @ptrToIntResult to i64), 0
|
||||
%zero = icmp eq i64 ptrtoint (ptr @ptrToIntResult to i64), 0
|
||||
br i1 %zero, label %a, label %b
|
||||
a:
|
||||
; should not be reached
|
||||
store i8 1, i8* @ptrToIntResult
|
||||
store i8 1, ptr @ptrToIntResult
|
||||
ret void
|
||||
b:
|
||||
; should be reached
|
||||
store i8 2, i8* @ptrToIntResult
|
||||
store i8 2, ptr @ptrToIntResult
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testConstGEP() {
|
||||
store i8* getelementptr inbounds (i8, i8* bitcast ({i16, i8, i8}* @someArray to i8*), i32 2), i8** @someArrayPointer
|
||||
store ptr getelementptr inbounds (i8, ptr @someArray, i32 2), ptr @someArrayPointer
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testICmp() {
|
||||
br i1 icmp eq (i64 ptrtoint (i8* @ptrToIntResult to i64), i64 0), label %equal, label %unequal
|
||||
br i1 icmp eq (i64 ptrtoint (ptr @ptrToIntResult to i64), i64 0), label %equal, label %unequal
|
||||
equal:
|
||||
; should not be reached
|
||||
store i8 1, i8* @icmpResult
|
||||
store i8 1, ptr @icmpResult
|
||||
ret void
|
||||
unequal:
|
||||
; should be reached
|
||||
store i8 2, i8* @icmpResult
|
||||
store i8 2, ptr @icmpResult
|
||||
ret void
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testPointerTag() {
|
||||
%val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3
|
||||
store i64 %val, ptr @pointerTagResult
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -4,8 +4,9 @@ target triple = "x86_64--linux"
|
||||
@intToPtrResult = local_unnamed_addr global i8 2
|
||||
@ptrToIntResult = local_unnamed_addr global i8 2
|
||||
@icmpResult = local_unnamed_addr global i8 2
|
||||
@pointerTagResult = local_unnamed_addr global i64 2
|
||||
@someArray = internal global { i16, i8, i8 } zeroinitializer
|
||||
@someArrayPointer = local_unnamed_addr global i8* getelementptr inbounds ({ i16, i8, i8 }, { i16, i8, i8 }* @someArray, i64 0, i32 1)
|
||||
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds ({ i16, i8, i8 }, ptr @someArray, i64 0, i32 1)
|
||||
|
||||
define void @runtime.initAll() local_unnamed_addr {
|
||||
ret void
|
||||
|
||||
Vendored
+9
-9
@@ -3,14 +3,14 @@ target triple = "x86_64--linux"
|
||||
|
||||
@main.v1 = global i1 0
|
||||
@main.v2 = global i1 0
|
||||
@"reflect/types.type:named:main.foo" = private constant { i8, i8*, i8* } { i8 34, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:named:main.foo", i32 0, i32 0), i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:basic:int", i32 0, i32 0) }, align 4
|
||||
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, i8* }
|
||||
@"reflect/types.type:named:main.foo" = private constant { i8, ptr, ptr } { i8 34, ptr @"reflect/types.type:pointer:named:main.foo", ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, ptr }
|
||||
@"reflect/types.typeid:named:main.foo" = external constant i8
|
||||
@"reflect/types.type:basic:int" = private constant { i8, i8* } { i8 2, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:basic:int", i32 0, i32 0) }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = external constant { i8, i8* }
|
||||
@"reflect/types.type:basic:int" = private constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = external constant { i8, ptr }
|
||||
|
||||
|
||||
declare i1 @runtime.typeAssert(i8*, i8*, i8*, i8*)
|
||||
declare i1 @runtime.typeAssert(ptr, ptr, ptr, ptr)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
@@ -21,9 +21,9 @@ entry:
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; Test type asserts.
|
||||
%typecode = call i1 @runtime.typeAssert(i8* getelementptr inbounds ({ i8, i8*, i8* }, { i8, i8*, i8* }* @"reflect/types.type:named:main.foo", i32 0, i32 0), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode, i1* @main.v1
|
||||
%typecode2 = call i1 @runtime.typeAssert(i8* null, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode2, i1* @main.v2
|
||||
%typecode = call i1 @runtime.typeAssert(ptr @"reflect/types.type:named:main.foo", ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
|
||||
store i1 %typecode, ptr @main.v1
|
||||
%typecode2 = call i1 @runtime.typeAssert(ptr null, ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
|
||||
store i1 %typecode2, ptr @main.v2
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -25,7 +25,7 @@ for.loop:
|
||||
br i1 %icmp, label %for.done, label %for.loop
|
||||
|
||||
for.done:
|
||||
store i8 %a, i8* @main.phiNodesResultA
|
||||
store i8 %b, i8* @main.phiNodesResultB
|
||||
store i8 %a, ptr @main.phiNodesResultA
|
||||
store i8 %b, ptr @main.phiNodesResultB
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+34
-37
@@ -3,7 +3,7 @@ target triple = "x86_64--linux"
|
||||
|
||||
declare void @externalCall(i64)
|
||||
|
||||
declare i64 @ptrHash(i8* nocapture)
|
||||
declare i64 @ptrHash(ptr nocapture)
|
||||
|
||||
@foo.knownAtRuntime = global i64 0
|
||||
@bar.knownAtRuntime = global i64 0
|
||||
@@ -17,60 +17,60 @@ declare i64 @ptrHash(i8* nocapture)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
call void @baz.init(i8* undef)
|
||||
call void @foo.init(i8* undef)
|
||||
call void @bar.init(i8* undef)
|
||||
call void @main.init(i8* undef)
|
||||
call void @x.init(i8* undef)
|
||||
call void @y.init(i8* undef)
|
||||
call void @z.init(i8* undef)
|
||||
call void @baz.init(ptr undef)
|
||||
call void @foo.init(ptr undef)
|
||||
call void @bar.init(ptr undef)
|
||||
call void @main.init(ptr undef)
|
||||
call void @x.init(ptr undef)
|
||||
call void @y.init(ptr undef)
|
||||
call void @z.init(ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime
|
||||
define internal void @foo.init(ptr %context) unnamed_addr {
|
||||
store i64 5, ptr @foo.knownAtRuntime
|
||||
unreachable ; this triggers a revert of @foo.init.
|
||||
}
|
||||
|
||||
define internal void @bar.init(i8* %context) unnamed_addr {
|
||||
%val = load i64, i64* @foo.knownAtRuntime
|
||||
store i64 %val, i64* @bar.knownAtRuntime
|
||||
define internal void @bar.init(ptr %context) unnamed_addr {
|
||||
%val = load i64, ptr @foo.knownAtRuntime
|
||||
store i64 %val, ptr @bar.knownAtRuntime
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @baz.init(i8* %context) unnamed_addr {
|
||||
define internal void @baz.init(ptr %context) unnamed_addr {
|
||||
; Test extractvalue/insertvalue with more than one index.
|
||||
%val = load [3 x {i64, i32}], [3 x {i64, i32}]* @baz.someGlobal
|
||||
%val = load [3 x {i64, i32}], ptr @baz.someGlobal
|
||||
%part = extractvalue [3 x {i64, i32}] %val, 0, 1
|
||||
%val2 = insertvalue [3 x {i64, i32}] %val, i32 5, 2, 1
|
||||
unreachable ; trigger revert
|
||||
}
|
||||
|
||||
define internal void @main.init(i8* %context) unnamed_addr {
|
||||
define internal void @main.init(ptr %context) unnamed_addr {
|
||||
entry:
|
||||
call void @externalCall(i64 3)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define internal void @x.init(i8* %context) unnamed_addr {
|
||||
define internal void @x.init(ptr %context) unnamed_addr {
|
||||
; Test atomic and volatile memory accesses.
|
||||
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, i32* @x.atomicNum
|
||||
%y = load volatile i32, i32* @x.volatileNum
|
||||
store volatile i32 %y, i32* @x.volatileNum
|
||||
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, ptr @x.atomicNum
|
||||
%y = load volatile i32, ptr @x.volatileNum
|
||||
store volatile i32 %y, ptr @x.volatileNum
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @y.init(i8* %context) unnamed_addr {
|
||||
define internal void @y.init(ptr %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
; Test a wait-loop.
|
||||
; This function must be reverted.
|
||||
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||
%val = load atomic i32, ptr @y.ready seq_cst, align 4
|
||||
%ready = icmp eq i32 %val, 1
|
||||
br i1 %ready, label %end, label %loop
|
||||
|
||||
@@ -78,27 +78,25 @@ end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.init(i8* %context) unnamed_addr {
|
||||
%bloom = bitcast i64* @z.bloom to i8*
|
||||
|
||||
define internal void @z.init(ptr %context) unnamed_addr {
|
||||
; This can be safely expanded.
|
||||
call void @z.setArr(i8* %bloom, i64 1, i8* %bloom)
|
||||
call void @z.setArr(ptr @z.bloom, i64 1, ptr @z.bloom)
|
||||
|
||||
; This call should be reverted to prevent unrolling.
|
||||
call void @z.setArr(i8* bitcast ([32 x i8]* @z.arr to i8*), i64 32, i8* %bloom)
|
||||
call void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
|
||||
define internal void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
|
||||
%idx = sub i64 %prev, 1
|
||||
%elem = getelementptr i8, i8* %arr, i64 %idx
|
||||
call void @z.set(i8* %elem, i8* %context)
|
||||
%elem = getelementptr i8, ptr %arr, i64 %idx
|
||||
call void @z.set(ptr %elem, ptr %context)
|
||||
%done = icmp eq i64 %idx, 0
|
||||
br i1 %done, label %end, label %loop
|
||||
|
||||
@@ -106,14 +104,13 @@ end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.set(i8* %ptr, i8* %context) unnamed_addr {
|
||||
define internal void @z.set(ptr %ptr, ptr %context) unnamed_addr {
|
||||
; Insert the pointer into the Bloom filter.
|
||||
%hash = call i64 @ptrHash(i8* %ptr)
|
||||
%hash = call i64 @ptrHash(ptr %ptr)
|
||||
%index = lshr i64 %hash, 58
|
||||
%bit = shl i64 1, %index
|
||||
%bloom = bitcast i8* %context to i64*
|
||||
%old = load i64, i64* %bloom
|
||||
%old = load i64, ptr %context
|
||||
%new = or i64 %old, %bit
|
||||
store i64 %new, i64* %bloom
|
||||
store i64 %new, ptr %context
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+27
-28
@@ -13,41 +13,41 @@ target triple = "x86_64--linux"
|
||||
|
||||
declare void @externalCall(i64) local_unnamed_addr
|
||||
|
||||
declare i64 @ptrHash(i8* nocapture) local_unnamed_addr
|
||||
declare i64 @ptrHash(ptr nocapture) local_unnamed_addr
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
call fastcc void @baz.init(i8* undef)
|
||||
call fastcc void @foo.init(i8* undef)
|
||||
%val = load i64, i64* @foo.knownAtRuntime, align 8
|
||||
store i64 %val, i64* @bar.knownAtRuntime, align 8
|
||||
call fastcc void @baz.init(ptr undef)
|
||||
call fastcc void @foo.init(ptr undef)
|
||||
%val = load i64, ptr @foo.knownAtRuntime, align 8
|
||||
store i64 %val, ptr @bar.knownAtRuntime, align 8
|
||||
call void @externalCall(i64 3)
|
||||
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, i32* @x.atomicNum, align 4
|
||||
%y = load volatile i32, i32* @x.volatileNum, align 4
|
||||
store volatile i32 %y, i32* @x.volatileNum, align 4
|
||||
call fastcc void @y.init(i8* undef)
|
||||
call fastcc void @z.set(i8* bitcast (i64* @z.bloom to i8*), i8* bitcast (i64* @z.bloom to i8*))
|
||||
call fastcc void @z.setArr(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @z.arr, i32 0, i32 0), i64 32, i8* bitcast (i64* @z.bloom to i8*))
|
||||
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, ptr @x.atomicNum, align 4
|
||||
%y = load volatile i32, ptr @x.volatileNum, align 4
|
||||
store volatile i32 %y, ptr @x.volatileNum, align 4
|
||||
call fastcc void @y.init(ptr undef)
|
||||
call fastcc void @z.set(ptr @z.bloom, ptr @z.bloom)
|
||||
call fastcc void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime, align 8
|
||||
define internal fastcc void @foo.init(ptr %context) unnamed_addr {
|
||||
store i64 5, ptr @foo.knownAtRuntime, align 8
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc void @baz.init(i8* %context) unnamed_addr {
|
||||
define internal fastcc void @baz.init(ptr %context) unnamed_addr {
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc void @y.init(i8* %context) unnamed_addr {
|
||||
define internal fastcc void @y.init(ptr %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop: ; preds = %loop, %entry
|
||||
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||
%val = load atomic i32, ptr @y.ready seq_cst, align 4
|
||||
%ready = icmp eq i32 %val, 1
|
||||
br i1 %ready, label %end, label %loop
|
||||
|
||||
@@ -55,15 +55,15 @@ end: ; preds = %loop
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
|
||||
define internal fastcc void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
|
||||
loop: ; preds = %loop, %entry
|
||||
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
|
||||
%idx = sub i64 %prev, 1
|
||||
%elem = getelementptr i8, i8* %arr, i64 %idx
|
||||
call fastcc void @z.set(i8* %elem, i8* %context)
|
||||
%elem = getelementptr i8, ptr %arr, i64 %idx
|
||||
call fastcc void @z.set(ptr %elem, ptr %context)
|
||||
%done = icmp eq i64 %idx, 0
|
||||
br i1 %done, label %end, label %loop
|
||||
|
||||
@@ -71,13 +71,12 @@ end: ; preds = %loop
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @z.set(i8* %ptr, i8* %context) unnamed_addr {
|
||||
%hash = call i64 @ptrHash(i8* %ptr)
|
||||
define internal fastcc void @z.set(ptr %ptr, ptr %context) unnamed_addr {
|
||||
%hash = call i64 @ptrHash(ptr %ptr)
|
||||
%index = lshr i64 %hash, 58
|
||||
%bit = shl i64 1, %index
|
||||
%bloom = bitcast i8* %context to i64*
|
||||
%old = load i64, i64* %bloom, align 8
|
||||
%old = load i64, ptr %context, align 8
|
||||
%new = or i64 %old, %bit
|
||||
store i64 %new, i64* %bloom, align 8
|
||||
store i64 %new, ptr %context, align 8
|
||||
ret void
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+32
-35
@@ -2,15 +2,15 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
@main.uint8SliceSrc.buf = internal global [2 x i8] c"\03d"
|
||||
@main.uint8SliceSrc = internal unnamed_addr global { i8*, i64, i64 } { i8* getelementptr inbounds ([2 x i8], [2 x i8]* @main.uint8SliceSrc.buf, i32 0, i32 0), i64 2, i64 2 }
|
||||
@main.uint8SliceDst = internal unnamed_addr global { i8*, i64, i64 } zeroinitializer
|
||||
@main.uint8SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.uint8SliceSrc.buf, i64 2, i64 2 }
|
||||
@main.uint8SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
|
||||
@main.int16SliceSrc.buf = internal global [3 x i16] [i16 5, i16 123, i16 1024]
|
||||
@main.int16SliceSrc = internal unnamed_addr global { i16*, i64, i64 } { i16* getelementptr inbounds ([3 x i16], [3 x i16]* @main.int16SliceSrc.buf, i32 0, i32 0), i64 3, i64 3 }
|
||||
@main.int16SliceDst = internal unnamed_addr global { i16*, i64, i64 } zeroinitializer
|
||||
@main.int16SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.int16SliceSrc.buf, i64 3, i64 3 }
|
||||
@main.int16SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
|
||||
|
||||
declare i64 @runtime.sliceCopy(i8* %dst, i8* %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
|
||||
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
|
||||
|
||||
declare i8* @runtime.alloc(i64, i8*) unnamed_addr
|
||||
declare ptr @runtime.alloc(i64, ptr) unnamed_addr
|
||||
|
||||
declare void @runtime.printuint8(i8)
|
||||
|
||||
@@ -25,23 +25,23 @@ entry:
|
||||
define void @main() unnamed_addr {
|
||||
entry:
|
||||
; print(uintSliceSrc[0])
|
||||
%uint8SliceSrc.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc, i64 0, i32 0)
|
||||
%uint8SliceSrc.val = load i8, i8* %uint8SliceSrc.buf
|
||||
%uint8SliceSrc.buf = load ptr, ptr @main.uint8SliceSrc
|
||||
%uint8SliceSrc.val = load i8, ptr %uint8SliceSrc.buf
|
||||
call void @runtime.printuint8(i8 %uint8SliceSrc.val)
|
||||
|
||||
; print(uintSliceDst[0])
|
||||
%uint8SliceDst.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceDst, i64 0, i32 0)
|
||||
%uint8SliceDst.val = load i8, i8* %uint8SliceDst.buf
|
||||
%uint8SliceDst.buf = load ptr, ptr @main.uint8SliceDst
|
||||
%uint8SliceDst.val = load i8, ptr %uint8SliceDst.buf
|
||||
call void @runtime.printuint8(i8 %uint8SliceDst.val)
|
||||
|
||||
; print(int16SliceSrc[0])
|
||||
%int16SliceSrc.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc, i64 0, i32 0)
|
||||
%int16SliceSrc.val = load i16, i16* %int16SliceSrc.buf
|
||||
%int16SliceSrc.buf = load ptr, ptr @main.int16SliceSrc
|
||||
%int16SliceSrc.val = load i16, ptr %int16SliceSrc.buf
|
||||
call void @runtime.printint16(i16 %int16SliceSrc.val)
|
||||
|
||||
; print(int16SliceDst[0])
|
||||
%int16SliceDst.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceDst, i64 0, i32 0)
|
||||
%int16SliceDst.val = load i16, i16* %int16SliceDst.buf
|
||||
%int16SliceDst.buf = load ptr, ptr @main.int16SliceDst
|
||||
%int16SliceDst.val = load i16, ptr %int16SliceDst.buf
|
||||
call void @runtime.printint16(i16 %int16SliceDst.val)
|
||||
ret void
|
||||
}
|
||||
@@ -50,37 +50,34 @@ define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; equivalent of:
|
||||
; uint8SliceDst = make([]uint8, len(uint8SliceSrc))
|
||||
%uint8SliceSrc = load { i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc
|
||||
%uint8SliceSrc.len = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 1
|
||||
%uint8SliceDst.buf = call i8* @runtime.alloc(i64 %uint8SliceSrc.len, i8* null)
|
||||
%0 = insertvalue { i8*, i64, i64 } undef, i8* %uint8SliceDst.buf, 0
|
||||
%1 = insertvalue { i8*, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
|
||||
%2 = insertvalue { i8*, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
|
||||
store { i8*, i64, i64 } %2, { i8*, i64, i64 }* @main.uint8SliceDst
|
||||
%uint8SliceSrc = load { ptr, i64, i64 }, ptr @main.uint8SliceSrc
|
||||
%uint8SliceSrc.len = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 1
|
||||
%uint8SliceDst.buf = call ptr @runtime.alloc(i64 %uint8SliceSrc.len, ptr null)
|
||||
%0 = insertvalue { ptr, i64, i64 } undef, ptr %uint8SliceDst.buf, 0
|
||||
%1 = insertvalue { ptr, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
|
||||
%2 = insertvalue { ptr, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
|
||||
store { ptr, i64, i64 } %2, ptr @main.uint8SliceDst
|
||||
|
||||
; equivalent of:
|
||||
; copy(uint8SliceDst, uint8SliceSrc)
|
||||
%uint8SliceSrc.buf = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 0
|
||||
%copy.n = call i64 @runtime.sliceCopy(i8* %uint8SliceDst.buf, i8* %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
|
||||
%uint8SliceSrc.buf = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 0
|
||||
%copy.n = call i64 @runtime.sliceCopy(ptr %uint8SliceDst.buf, ptr %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
|
||||
|
||||
; equivalent of:
|
||||
; int16SliceDst = make([]int16, len(int16SliceSrc))
|
||||
%int16SliceSrc = load { i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc
|
||||
%int16SliceSrc.len = extractvalue { i16*, i64, i64 } %int16SliceSrc, 1
|
||||
%int16SliceSrc = load { ptr, i64, i64 }, ptr @main.int16SliceSrc
|
||||
%int16SliceSrc.len = extractvalue { ptr, i64, i64 } %int16SliceSrc, 1
|
||||
%int16SliceSrc.len.bytes = mul i64 %int16SliceSrc.len, 2
|
||||
%int16SliceDst.buf.raw = call i8* @runtime.alloc(i64 %int16SliceSrc.len.bytes, i8* null)
|
||||
%int16SliceDst.buf = bitcast i8* %int16SliceDst.buf.raw to i16*
|
||||
%3 = insertvalue { i16*, i64, i64 } undef, i16* %int16SliceDst.buf, 0
|
||||
%4 = insertvalue { i16*, i64, i64 } %3, i64 %int16SliceSrc.len, 1
|
||||
%5 = insertvalue { i16*, i64, i64 } %4, i64 %int16SliceSrc.len, 2
|
||||
store { i16*, i64, i64 } %5, { i16*, i64, i64 }* @main.int16SliceDst
|
||||
%int16SliceDst.buf = call ptr @runtime.alloc(i64 %int16SliceSrc.len.bytes, ptr null)
|
||||
%3 = insertvalue { ptr, i64, i64 } undef, ptr %int16SliceDst.buf, 0
|
||||
%4 = insertvalue { ptr, i64, i64 } %3, i64 %int16SliceSrc.len, 1
|
||||
%5 = insertvalue { ptr, i64, i64 } %4, i64 %int16SliceSrc.len, 2
|
||||
store { ptr, i64, i64 } %5, ptr @main.int16SliceDst
|
||||
|
||||
; equivalent of:
|
||||
; copy(int16SliceDst, int16SliceSrc)
|
||||
%int16SliceSrc.buf = extractvalue { i16*, i64, i64 } %int16SliceSrc, 0
|
||||
%int16SliceSrc.buf.i8ptr = bitcast i16* %int16SliceSrc.buf to i8*
|
||||
%int16SliceDst.buf.i8ptr = bitcast i16* %int16SliceDst.buf to i8*
|
||||
%copy.n2 = call i64 @runtime.sliceCopy(i8* %int16SliceDst.buf.i8ptr, i8* %int16SliceSrc.buf.i8ptr, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
|
||||
%int16SliceSrc.buf = extractvalue { ptr, i64, i64 } %int16SliceSrc, 0
|
||||
%copy.n2 = call i64 @runtime.sliceCopy(ptr %int16SliceDst.buf, ptr %int16SliceSrc.buf, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
+1
-1
@@ -231,8 +231,8 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/fuzz/": false,
|
||||
"internal/bytealg/": false,
|
||||
"internal/fuzz/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/task/": false,
|
||||
"machine/": false,
|
||||
|
||||
@@ -216,39 +216,58 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
|
||||
|
||||
// Test runs the tests in the given package. Returns whether the test passed and
|
||||
// possibly an error if the test failed to run.
|
||||
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string, testBenchMem bool, outpath string) (bool, error) {
|
||||
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, outpath string) (bool, error) {
|
||||
options.TestConfig.CompileTestBinary = true
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
testConfig := &options.TestConfig
|
||||
|
||||
// Pass test flags to the test binary.
|
||||
var flags []string
|
||||
if testVerbose {
|
||||
if testConfig.Verbose {
|
||||
flags = append(flags, "-test.v")
|
||||
}
|
||||
if testShort {
|
||||
if testConfig.Short {
|
||||
flags = append(flags, "-test.short")
|
||||
}
|
||||
if testRunRegexp != "" {
|
||||
flags = append(flags, "-test.run="+testRunRegexp)
|
||||
if testConfig.RunRegexp != "" {
|
||||
flags = append(flags, "-test.run="+testConfig.RunRegexp)
|
||||
}
|
||||
if testBenchRegexp != "" {
|
||||
flags = append(flags, "-test.bench="+testBenchRegexp)
|
||||
if testConfig.SkipRegexp != "" {
|
||||
flags = append(flags, "-test.skip="+testConfig.SkipRegexp)
|
||||
}
|
||||
if testBenchTime != "" {
|
||||
flags = append(flags, "-test.benchtime="+testBenchTime)
|
||||
if testConfig.BenchRegexp != "" {
|
||||
flags = append(flags, "-test.bench="+testConfig.BenchRegexp)
|
||||
}
|
||||
if testBenchMem {
|
||||
if testConfig.BenchTime != "" {
|
||||
flags = append(flags, "-test.benchtime="+testConfig.BenchTime)
|
||||
}
|
||||
if testConfig.BenchMem {
|
||||
flags = append(flags, "-test.benchmem")
|
||||
}
|
||||
if testConfig.Count != nil && *testConfig.Count != 1 {
|
||||
flags = append(flags, "-test.count="+strconv.Itoa(*testConfig.Count))
|
||||
}
|
||||
if testConfig.Shuffle != "" {
|
||||
flags = append(flags, "-test.shuffle="+testConfig.Shuffle)
|
||||
}
|
||||
|
||||
logToStdout := testConfig.Verbose || testConfig.BenchRegexp != ""
|
||||
|
||||
var buf bytes.Buffer
|
||||
var output io.Writer = &buf
|
||||
// Send the test output to stdout if -v or -bench
|
||||
if logToStdout {
|
||||
output = os.Stdout
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
passed := false
|
||||
var duration time.Duration
|
||||
result, err := buildAndRun(pkgName, config, &buf, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
if testCompileOnly || outpath != "" {
|
||||
result, err := buildAndRun(pkgName, config, output, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
if testConfig.CompileOnly || outpath != "" {
|
||||
// Write test binary to the specified file name.
|
||||
if outpath == "" {
|
||||
// No -o path was given, so create one now.
|
||||
@@ -257,7 +276,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
}
|
||||
copyFile(result.Binary, outpath)
|
||||
}
|
||||
if testCompileOnly {
|
||||
if testConfig.CompileOnly {
|
||||
// Do not run the test.
|
||||
passed = true
|
||||
return nil
|
||||
@@ -305,11 +324,9 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
duration = time.Since(start)
|
||||
passed = err == nil
|
||||
|
||||
// print the test output if
|
||||
// 1) the tests passed and in verbose mode
|
||||
// 2) the tests failed
|
||||
// 3) running benchmarks
|
||||
if (passed && testVerbose) || (!passed) || (testBenchRegexp != "") {
|
||||
// if verbose or benchmarks, then output is already going to stdout
|
||||
// However, if we failed and weren't printing to stdout, print the output we accumulated.
|
||||
if !passed && !logToStdout {
|
||||
buf.WriteTo(stdout)
|
||||
}
|
||||
|
||||
@@ -322,14 +339,19 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
return err
|
||||
})
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
|
||||
var w io.Writer = stdout
|
||||
if logToStdout {
|
||||
w = os.Stdout
|
||||
}
|
||||
if err, ok := err.(loader.NoTestFilesError); ok {
|
||||
fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
fmt.Fprintf(w, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
// Pretend the test passed - it at least didn't fail.
|
||||
return true, nil
|
||||
} else if passed {
|
||||
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else if passed && !testConfig.CompileOnly {
|
||||
fmt.Fprintf(w, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
fmt.Fprintf(w, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
}
|
||||
return passed, err
|
||||
}
|
||||
@@ -510,7 +532,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||
}
|
||||
if options.Monitor {
|
||||
return Monitor("", options)
|
||||
return Monitor(result.Executable, "", options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -776,6 +798,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
}
|
||||
}
|
||||
var args, env []string
|
||||
var extraCmdEnv []string
|
||||
if needsEnvInVars {
|
||||
runtimeGlobals := make(map[string]string)
|
||||
if len(cmdArgs) != 0 {
|
||||
@@ -806,6 +829,11 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
args = append(args, "--")
|
||||
args = append(args, cmdArgs...)
|
||||
}
|
||||
|
||||
// Set this for nicer backtraces during tests, but don't override the user.
|
||||
if _, ok := os.LookupEnv("WASMTIME_BACKTRACE_DETAILS"); !ok {
|
||||
extraCmdEnv = append(extraCmdEnv, "WASMTIME_BACKTRACE_DETAILS=1")
|
||||
}
|
||||
} else {
|
||||
// Pass environment variables and command line parameters as usual.
|
||||
// This also works on qemu-aarch64 etc.
|
||||
@@ -857,7 +885,8 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
} else {
|
||||
cmd = exec.Command(name, args...)
|
||||
}
|
||||
cmd.Env = env
|
||||
cmd.Env = append(cmd.Env, env...)
|
||||
cmd.Env = append(cmd.Env, extraCmdEnv...)
|
||||
|
||||
// Configure stdout/stderr. The stdout may go to a buffer, not a real
|
||||
// stdout.
|
||||
@@ -916,28 +945,29 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
||||
return fmt.Errorf("opening port: %s", err)
|
||||
}
|
||||
|
||||
func flashUF2UsingMSD(volume, tmppath string, options *compileopts.Options) error {
|
||||
func flashUF2UsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||
// find standard UF2 info path
|
||||
var infoPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
infoPath = "/media/*/" + volume + "/INFO_UF2.TXT"
|
||||
} else {
|
||||
infoPath = "/run/media/*/" + volume + "/INFO_UF2.TXT"
|
||||
infoPaths := make([]string, 0, len(volumes))
|
||||
for _, volume := range volumes {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
infoPaths = append(infoPaths, "/media/*/"+volume+"/INFO_UF2.TXT")
|
||||
} else {
|
||||
infoPaths = append(infoPaths, "/run/media/*/"+volume+"/INFO_UF2.TXT")
|
||||
}
|
||||
case "darwin":
|
||||
infoPaths = append(infoPaths, "/Volumes/"+volume+"/INFO_UF2.TXT")
|
||||
case "windows":
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err == nil {
|
||||
infoPaths = append(infoPaths, path+"/INFO_UF2.TXT")
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
infoPath = "/Volumes/" + volume + "/INFO_UF2.TXT"
|
||||
case "windows":
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
infoPath = path + "/INFO_UF2.TXT"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, infoPath, options.Timeout)
|
||||
d, err := locateDevice(volumes, infoPaths, options.Timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -945,28 +975,29 @@ func flashUF2UsingMSD(volume, tmppath string, options *compileopts.Options) erro
|
||||
return moveFile(tmppath, filepath.Dir(d)+"/flash.uf2")
|
||||
}
|
||||
|
||||
func flashHexUsingMSD(volume, tmppath string, options *compileopts.Options) error {
|
||||
func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||
// find expected volume path
|
||||
var destPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
destPath = "/media/*/" + volume
|
||||
} else {
|
||||
destPath = "/run/media/*/" + volume
|
||||
destPaths := make([]string, 0, len(volumes))
|
||||
for _, volume := range volumes {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
destPaths = append(destPaths, "/media/*/"+volume)
|
||||
} else {
|
||||
destPaths = append(destPaths, "/run/media/*/"+volume)
|
||||
}
|
||||
case "darwin":
|
||||
destPaths = append(destPaths, "/Volumes/"+volume)
|
||||
case "windows":
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err == nil {
|
||||
destPaths = append(destPaths, path+"/")
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
destPath = "/Volumes/" + volume
|
||||
case "windows":
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destPath = path + "/"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, destPath, options.Timeout)
|
||||
d, err := locateDevice(volumes, destPaths, options.Timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -974,21 +1005,28 @@ func flashHexUsingMSD(volume, tmppath string, options *compileopts.Options) erro
|
||||
return moveFile(tmppath, d+"/flash.hex")
|
||||
}
|
||||
|
||||
func locateDevice(volume, path string, timeout time.Duration) (string, error) {
|
||||
func locateDevice(volumes, paths []string, timeout time.Duration) (string, error) {
|
||||
var d []string
|
||||
var err error
|
||||
for start := time.Now(); time.Since(start) < timeout; {
|
||||
d, err = filepath.Glob(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
for _, path := range paths {
|
||||
d, err = filepath.Glob(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if d != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if d != nil {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
if d == nil {
|
||||
return "", errors.New("unable to locate device: " + volume)
|
||||
return "", errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||
}
|
||||
return d[0], nil
|
||||
}
|
||||
@@ -1363,9 +1401,6 @@ func main() {
|
||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
||||
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
||||
printIR := flag.Bool("printir", false, "print LLVM IR")
|
||||
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
||||
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
||||
var tags buildutil.TagsFlag
|
||||
flag.Var(&tags, "tags", "a space-separated list of extra build tags")
|
||||
target := flag.String("target", "", "chip/board name or JSON target specification file")
|
||||
@@ -1392,6 +1427,17 @@ func main() {
|
||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||
|
||||
// Internal flags, that are only intended for TinyGo development.
|
||||
printIR := flag.Bool("internal-printir", false, "print LLVM IR")
|
||||
dumpSSA := flag.Bool("internal-dumpssa", false, "dump internal Go SSA")
|
||||
verifyIR := flag.Bool("internal-verifyir", false, "run extra verification steps on LLVM IR")
|
||||
// Don't generate debug information in the IR, to make IR more readable.
|
||||
// You generally want debug information in IR for various features, like
|
||||
// stack size calculation and features like -size=short, -print-allocs=,
|
||||
// etc. The -no-debug flag is used to strip it at link time. But for TinyGo
|
||||
// development it can be useful to not emit debug information at all.
|
||||
skipDwarf := flag.Bool("internal-nodwarf", false, "internal flag, use -no-debug instead")
|
||||
|
||||
var flagJSON, flagDeps, flagTest bool
|
||||
if command == "help" || command == "list" || command == "info" || command == "build" {
|
||||
flag.BoolVar(&flagJSON, "json", false, "print data in JSON format")
|
||||
@@ -1404,19 +1450,19 @@ func main() {
|
||||
if command == "help" || command == "build" || command == "build-library" || command == "test" {
|
||||
flag.StringVar(&outpath, "o", "", "output filename")
|
||||
}
|
||||
var testCompileOnlyFlag, testVerboseFlag, testShortFlag *bool
|
||||
var testBenchRegexp *string
|
||||
var testBenchTime *string
|
||||
var testRunRegexp *string
|
||||
var testBenchMem *bool
|
||||
|
||||
var testConfig compileopts.TestConfig
|
||||
if command == "help" || command == "test" {
|
||||
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
|
||||
testVerboseFlag = flag.Bool("v", false, "verbose: print additional output")
|
||||
testShortFlag = flag.Bool("short", false, "short: run smaller test suite to save time")
|
||||
testRunRegexp = flag.String("run", "", "run: regexp of tests to run")
|
||||
testBenchRegexp = flag.String("bench", "", "run: regexp of benchmarks to run")
|
||||
testBenchTime = flag.String("benchtime", "", "run each benchmark for duration `d`")
|
||||
testBenchMem = flag.Bool("benchmem", false, "show memory stats for benchmarks")
|
||||
flag.BoolVar(&testConfig.CompileOnly, "c", false, "compile the test binary but do not run it")
|
||||
flag.BoolVar(&testConfig.Verbose, "v", false, "verbose: print additional output")
|
||||
flag.BoolVar(&testConfig.Short, "short", false, "short: run smaller test suite to save time")
|
||||
flag.StringVar(&testConfig.RunRegexp, "run", "", "run: regexp of tests to run")
|
||||
flag.StringVar(&testConfig.SkipRegexp, "skip", "", "skip: regexp of tests to skip")
|
||||
testConfig.Count = flag.Int("count", 1, "count: number of times to run tests/benchmarks `count` times")
|
||||
flag.StringVar(&testConfig.BenchRegexp, "bench", "", "bench: regexp of benchmarks to run")
|
||||
flag.StringVar(&testConfig.BenchTime, "benchtime", "", "run each benchmark for duration `d`")
|
||||
flag.BoolVar(&testConfig.BenchMem, "benchmem", false, "show memory stats for benchmarks")
|
||||
flag.StringVar(&testConfig.Shuffle, "shuffle", "", "shuffle the order the tests and benchmarks run")
|
||||
}
|
||||
|
||||
// Early command processing, before commands are interpreted by the Go flag
|
||||
@@ -1468,12 +1514,14 @@ func main() {
|
||||
PrintIR: *printIR,
|
||||
DumpSSA: *dumpSSA,
|
||||
VerifyIR: *verifyIR,
|
||||
SkipDWARF: *skipDwarf,
|
||||
Semaphore: make(chan struct{}, *parallelism),
|
||||
Debug: !*nodebug,
|
||||
PrintSizes: *printSize,
|
||||
PrintStacks: *printStacks,
|
||||
PrintAllocs: printAllocs,
|
||||
Tags: []string(tags),
|
||||
TestConfig: testConfig,
|
||||
GlobalValues: globalVarValues,
|
||||
Programmer: *programmer,
|
||||
OpenOCDCommands: ocdCommands,
|
||||
@@ -1650,7 +1698,7 @@ func main() {
|
||||
defer close(buf.done)
|
||||
stdout := (*testStdout)(buf)
|
||||
stderr := (*testStderr)(buf)
|
||||
passed, err := Test(pkgName, stdout, stderr, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, *testBenchRegexp, *testBenchTime, *testBenchMem, outpath)
|
||||
passed, err := Test(pkgName, stdout, stderr, options, outpath)
|
||||
if err != nil {
|
||||
printCompilerError(func(args ...interface{}) {
|
||||
fmt.Fprintln(stderr, args...)
|
||||
@@ -1672,7 +1720,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
case "monitor":
|
||||
err := Monitor(*port, options)
|
||||
err := Monitor("", *port, options)
|
||||
handleCompilerError(err)
|
||||
case "targets":
|
||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||
|
||||
+4
-4
@@ -425,7 +425,7 @@ func TestTest(t *testing.T) {
|
||||
defer out.Close()
|
||||
|
||||
opts := targ.opts
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "", "", false, "")
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, "")
|
||||
if err != nil {
|
||||
t.Errorf("test error: %v", err)
|
||||
}
|
||||
@@ -446,7 +446,7 @@ func TestTest(t *testing.T) {
|
||||
defer out.Close()
|
||||
|
||||
opts := targ.opts
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "", "", false, "")
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, "")
|
||||
if err != nil {
|
||||
t.Errorf("test error: %v", err)
|
||||
}
|
||||
@@ -473,7 +473,7 @@ func TestTest(t *testing.T) {
|
||||
|
||||
var output bytes.Buffer
|
||||
opts := targ.opts
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "", "", false, "")
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, "")
|
||||
if err != nil {
|
||||
t.Errorf("test error: %v", err)
|
||||
}
|
||||
@@ -497,7 +497,7 @@ func TestTest(t *testing.T) {
|
||||
defer out.Close()
|
||||
|
||||
opts := targ.opts
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "", "", false, "")
|
||||
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, "")
|
||||
if err == nil {
|
||||
t.Error("test did not error")
|
||||
}
|
||||
|
||||
+134
-5
@@ -1,9 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-tty"
|
||||
@@ -13,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
// Monitor connects to the given port and reads/writes the serial port.
|
||||
func Monitor(port string, options *compileopts.Options) error {
|
||||
func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -74,17 +83,31 @@ func Monitor(port string, options *compileopts.Options) error {
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 100*1024)
|
||||
var line []byte
|
||||
for {
|
||||
n, err := p.Read(buf)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("read error: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
continue
|
||||
start := 0
|
||||
for i, c := range buf[:n] {
|
||||
if c == '\n' {
|
||||
os.Stdout.Write(buf[start : i+1])
|
||||
start = i + 1
|
||||
address := extractPanicAddress(line)
|
||||
if address != 0 {
|
||||
loc, err := addressToLine(executable, address)
|
||||
if err == nil && loc.IsValid() {
|
||||
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
|
||||
}
|
||||
}
|
||||
line = line[:0]
|
||||
} else {
|
||||
line = append(line, c)
|
||||
}
|
||||
}
|
||||
fmt.Printf("%v", string(buf[:n]))
|
||||
os.Stdout.Write(buf[start:n])
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -104,3 +127,109 @@ func Monitor(port string, options *compileopts.Options) error {
|
||||
|
||||
return <-errCh
|
||||
}
|
||||
|
||||
var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `)
|
||||
|
||||
// Extract the address from the "panic: runtime error at" message.
|
||||
func extractPanicAddress(line []byte) uint64 {
|
||||
matches := addressMatch.FindSubmatch(line)
|
||||
if matches != nil {
|
||||
address, err := strconv.ParseUint(string(matches[1]), 16, 64)
|
||||
if err == nil {
|
||||
return address
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert an address in the binary to a source address location.
|
||||
func addressToLine(executable string, address uint64) (token.Position, error) {
|
||||
data, err := readDWARF(executable)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
r := data.Reader()
|
||||
|
||||
for {
|
||||
e, err := r.Next()
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
switch e.Tag {
|
||||
case dwarf.TagCompileUnit:
|
||||
r.SkipChildren()
|
||||
lr, err := data.LineReader(e)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
var lineEntry = dwarf.LineEntry{
|
||||
EndSequence: true,
|
||||
}
|
||||
for {
|
||||
// Read the next .debug_line entry.
|
||||
prevLineEntry := lineEntry
|
||||
err := lr.Next(&lineEntry)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return token.Position{}, err
|
||||
}
|
||||
|
||||
if prevLineEntry.EndSequence && lineEntry.Address == 0 {
|
||||
// Tombstone value. This symbol has been removed, for
|
||||
// example by the --gc-sections linker flag. It is still
|
||||
// here in the debug information because the linker can't
|
||||
// just remove this reference.
|
||||
// Read until the next EndSequence so that this sequence is
|
||||
// skipped.
|
||||
// For more details, see (among others):
|
||||
// https://reviews.llvm.org/D84825
|
||||
for {
|
||||
err := lr.Next(&lineEntry)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
if lineEntry.EndSequence {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !prevLineEntry.EndSequence {
|
||||
// The chunk describes the code from prevLineEntry to
|
||||
// lineEntry.
|
||||
if prevLineEntry.Address <= address && lineEntry.Address > address {
|
||||
return token.Position{
|
||||
Filename: prevLineEntry.File.Name,
|
||||
Line: prevLineEntry.Line,
|
||||
Column: prevLineEntry.Column,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return token.Position{}, nil // location not found
|
||||
}
|
||||
|
||||
// Read the DWARF debug information from a given file (in various formats).
|
||||
func readDWARF(executable string) (*dwarf.Data, error) {
|
||||
f, err := os.Open(executable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file, err := elf.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else if file, err := macho.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else if file, err := pe.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else {
|
||||
return nil, errors.New("unknown binary format")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
func TestTraceback(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
// We care about testing the ELF format, which is only used on Linux
|
||||
// (not on MacOS or Windows).
|
||||
t.Skip("Test only works on Linux")
|
||||
}
|
||||
|
||||
// Build a small binary that only panics.
|
||||
tmpdir := t.TempDir()
|
||||
config, err := builder.NewConfig(&compileopts.Options{
|
||||
GOOS: runtime.GOOS,
|
||||
GOARCH: runtime.GOARCH,
|
||||
Opt: "z",
|
||||
InterpTimeout: time.Minute,
|
||||
Debug: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := builder.Build("testdata/trivialpanic.go", ".elf", tmpdir, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Run this binary, and capture the output.
|
||||
buf := &bytes.Buffer{}
|
||||
cmd := exec.Command(result.Binary)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
cmd.Run() // this will return an error because of the panic, ignore it
|
||||
|
||||
// Extract the "runtime error at" address.
|
||||
line := bytes.TrimSpace(buf.Bytes())
|
||||
address := extractPanicAddress(line)
|
||||
if address == 0 {
|
||||
t.Fatalf("could not extract panic address from %#v", string(line))
|
||||
}
|
||||
|
||||
// Look up the source location for this address.
|
||||
location, err := addressToLine(result.Executable, address)
|
||||
if err != nil {
|
||||
t.Fatal("could not read source location:", err)
|
||||
}
|
||||
|
||||
// Verify that the source location is as expected.
|
||||
if filepath.Base(location.Filename) != "trivialpanic.go" {
|
||||
t.Errorf("expected path to end with trivialpanic.go, got %#v", location.Filename)
|
||||
}
|
||||
if location.Line != 6 {
|
||||
t.Errorf("expected panic location to be line 6, got line %d", location.Line)
|
||||
}
|
||||
}
|
||||
+7
-11
@@ -29,6 +29,7 @@
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
package arm
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"runtime/volatile"
|
||||
@@ -174,20 +175,15 @@ func SetPriority(irq uint32, priority uint32) {
|
||||
|
||||
// DisableInterrupts disables all interrupts, and returns the old interrupt
|
||||
// state.
|
||||
func DisableInterrupts() uintptr {
|
||||
return AsmFull(`
|
||||
mrs {}, PRIMASK
|
||||
cpsid i
|
||||
`, nil)
|
||||
}
|
||||
//
|
||||
//export DisableInterrupts
|
||||
func DisableInterrupts() uintptr
|
||||
|
||||
// EnableInterrupts enables all interrupts again. The value passed in must be
|
||||
// the mask returned by DisableInterrupts.
|
||||
func EnableInterrupts(mask uintptr) {
|
||||
AsmFull("msr PRIMASK, {mask}", map[string]interface{}{
|
||||
"mask": mask,
|
||||
})
|
||||
}
|
||||
//
|
||||
//export EnableInterrupts
|
||||
func EnableInterrupts(mask uintptr)
|
||||
|
||||
// Set up the system timer to generate periodic tick events.
|
||||
// This will cause SysTick_Handler to fire once per tick.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void EnableInterrupts(uintptr_t mask) {
|
||||
asm volatile(
|
||||
"msr PRIMASK, %0"
|
||||
:
|
||||
: "r"(mask)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
uintptr_t DisableInterrupts() {
|
||||
uintptr_t mask;
|
||||
asm volatile(
|
||||
"mrs %0, PRIMASK\n\t"
|
||||
"cpsid i"
|
||||
: "=r"(mask)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return mask;
|
||||
}
|
||||
@@ -0,0 +1,827 @@
|
||||
// Hand written file mostly derived from https://problemkaputt.de/gbatek.htm
|
||||
|
||||
//go:build gameboyadvance
|
||||
|
||||
package gba
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Interrupt numbers.
|
||||
const (
|
||||
IRQ_VBLANK = 0
|
||||
IRQ_HBLANK = 1
|
||||
IRQ_VCOUNT = 2
|
||||
IRQ_TIMER0 = 3
|
||||
IRQ_TIMER1 = 4
|
||||
IRQ_TIMER2 = 5
|
||||
IRQ_TIMER3 = 6
|
||||
IRQ_COM = 7
|
||||
IRQ_DMA0 = 8
|
||||
IRQ_DMA1 = 9
|
||||
IRQ_DMA2 = 10
|
||||
IRQ_DMA3 = 11
|
||||
IRQ_KEYPAD = 12
|
||||
IRQ_GAMEPAK = 13
|
||||
)
|
||||
|
||||
// Peripherals
|
||||
var (
|
||||
// Display registers
|
||||
DISP = (*DISP_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0000)))
|
||||
|
||||
// Background control registers
|
||||
BGCNT0 = (*BGCNT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0008)))
|
||||
BGCNT1 = (*BGCNT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x000A)))
|
||||
BGCNT2 = (*BGCNT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x000C)))
|
||||
BGCNT3 = (*BGCNT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x000E)))
|
||||
|
||||
BG0 = (*BG_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0010)))
|
||||
BG1 = (*BG_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0014)))
|
||||
BG2 = (*BG_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0018)))
|
||||
BG3 = (*BG_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x001C)))
|
||||
|
||||
BGA2 = (*BG_AFFINE_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0020)))
|
||||
BGA3 = (*BG_AFFINE_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0030)))
|
||||
|
||||
WIN = (*WIN_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0040)))
|
||||
|
||||
GRAPHICS = (*GRAPHICS_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x004C)))
|
||||
|
||||
// GBA Sound Channel 1 - Tone & Sweep
|
||||
SOUND1 = (*SOUND1_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0060)))
|
||||
|
||||
// GBA Sound Channel 2 - Tone
|
||||
SOUND2 = (*SOUND2_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0068)))
|
||||
|
||||
// GBA Sound Channel 3 - Wave Output
|
||||
SOUND3 = (*SOUND3_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0070)))
|
||||
|
||||
// GBA Sound Channel 4 - Noise
|
||||
SOUND4 = (*SOUND4_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0078)))
|
||||
|
||||
// GBA Sound Control
|
||||
SOUND = (*SOUND_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0080)))
|
||||
|
||||
DMA0 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00B0)))
|
||||
DMA1 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00BC)))
|
||||
DMA2 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00C8)))
|
||||
DMA3 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00D4)))
|
||||
|
||||
TM0 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0100)))
|
||||
TM1 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0104)))
|
||||
TM2 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0108)))
|
||||
TM3 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x010C)))
|
||||
|
||||
// Communication 1
|
||||
SIODATA32 = (*SIODATA32_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0120)))
|
||||
SIOMULTI = (*SIOMULTI_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0120)))
|
||||
|
||||
KEY = (*KEY_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0130)))
|
||||
|
||||
// Communication 2
|
||||
SIO = (*SIO_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0134)))
|
||||
|
||||
INTERRUPT = (*INTERRUPT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0200)))
|
||||
)
|
||||
|
||||
// Main memory sections
|
||||
const (
|
||||
// External work RAM
|
||||
MEM_EWRAM uintptr = 0x02000000
|
||||
|
||||
// Internal work RAM
|
||||
MEM_IWRAM uintptr = 0x03000000
|
||||
|
||||
// I/O registers
|
||||
MEM_IO uintptr = 0x04000000
|
||||
|
||||
// Palette. Note: no 8bit write !!
|
||||
MEM_PAL uintptr = 0x05000000
|
||||
|
||||
// Video RAM. Note: no 8bit write !!
|
||||
MEM_VRAM uintptr = 0x06000000
|
||||
|
||||
// Object Attribute Memory (OAM) Note: no 8bit write !!
|
||||
MEM_OAM uintptr = 0x07000000
|
||||
|
||||
// ROM. No write at all (duh)
|
||||
MEM_ROM uintptr = 0x08000000
|
||||
|
||||
// Static RAM. 8bit write only
|
||||
MEM_SRAM uintptr = 0x0E000000
|
||||
)
|
||||
|
||||
// Main section sizes
|
||||
const (
|
||||
EWRAM_SIZE uintptr = 0x40000
|
||||
IWRAM_SIZE uintptr = 0x08000
|
||||
PAL_SIZE uintptr = 0x00400
|
||||
VRAM_SIZE uintptr = 0x18000
|
||||
OAM_SIZE uintptr = 0x00400
|
||||
SRAM_SIZE uintptr = 0x10000
|
||||
)
|
||||
|
||||
// Sub section sizes
|
||||
const (
|
||||
// BG palette size
|
||||
PAL_BG_SIZE = 0x00200
|
||||
|
||||
// Object palette size
|
||||
PAL_OBJ_SIZE = 0x00200
|
||||
|
||||
// Charblock size
|
||||
CBB_SIZE = 0x04000
|
||||
|
||||
// Screenblock size
|
||||
SBB_SIZE = 0x00800
|
||||
|
||||
// BG VRAM_MODE_0_2 size
|
||||
VRAM_BG_SIZE_MODE_0_2 = 0x10000
|
||||
|
||||
// BG VRAM size
|
||||
VRAM_BG_SIZE_MODE_3_5 = 0x14000
|
||||
|
||||
// Object VRAM size
|
||||
VRAM_OBJ_SIZE = 0x08000
|
||||
|
||||
// Mode 3 buffer size
|
||||
M3_SIZE = 0x12C00
|
||||
|
||||
// Mode 4 buffer size
|
||||
M4_SIZE = 0x09600
|
||||
|
||||
// Mode 5 buffer size
|
||||
M5_SIZE = 0x0A000
|
||||
|
||||
// Bitmap page size
|
||||
VRAM_PAGE_SIZE = 0x0A000
|
||||
)
|
||||
|
||||
// Sub sections
|
||||
var (
|
||||
REG_BASE uintptr = MEM_IO
|
||||
|
||||
// Background palette address
|
||||
MEM_PAL_BG = MEM_PAL
|
||||
|
||||
// Object palette address
|
||||
MEM_PAL_OBJ = MEM_PAL + PAL_BG_SIZE
|
||||
|
||||
// Front page address
|
||||
MEM_VRAM_FRONT = MEM_VRAM
|
||||
|
||||
// Back page address
|
||||
MEM_VRAM_BACK = MEM_VRAM + VRAM_PAGE_SIZE
|
||||
|
||||
// Object VRAM address - BG Mode 0-2
|
||||
MEM_VRAM_OBJ_MODE0_2 = MEM_VRAM + VRAM_BG_SIZE_MODE_0_2
|
||||
|
||||
// Object VRAM address - BG Mode 3-5
|
||||
MEM_VRAM_OBJ_MODE_3_5 = MEM_VRAM + VRAM_BG_SIZE_MODE_3_5
|
||||
)
|
||||
|
||||
// Display registers
|
||||
type DISP_Type struct {
|
||||
DISPCNT volatile.Register16
|
||||
_ [2]byte
|
||||
DISPSTAT volatile.Register16
|
||||
VCOUNT volatile.Register16
|
||||
}
|
||||
|
||||
// Background control registers
|
||||
type BGCNT_Type struct {
|
||||
CNT volatile.Register16
|
||||
}
|
||||
|
||||
// Regular background scroll registers. (write only!)
|
||||
type BG_Type struct {
|
||||
HOFS volatile.Register16
|
||||
VOFS volatile.Register16
|
||||
}
|
||||
|
||||
// Affine background parameters. (write only!)
|
||||
type BG_AFFINE_Type struct {
|
||||
PA volatile.Register16
|
||||
PB volatile.Register16
|
||||
PC volatile.Register16
|
||||
PD volatile.Register16
|
||||
X volatile.Register32
|
||||
Y volatile.Register32
|
||||
}
|
||||
|
||||
type WIN_Type struct {
|
||||
// win0 right, left (0xLLRR)
|
||||
WIN0H volatile.Register16
|
||||
|
||||
// win1 right, left (0xLLRR)
|
||||
WIN1H volatile.Register16
|
||||
|
||||
// win0 bottom, top (0xTTBB)
|
||||
WIN0V volatile.Register16
|
||||
|
||||
// win1 bottom, top (0xTTBB)
|
||||
WIN1V volatile.Register16
|
||||
|
||||
// win0, win1 control
|
||||
IN volatile.Register16
|
||||
|
||||
// winOut, winObj control
|
||||
OUT volatile.Register16
|
||||
}
|
||||
|
||||
type GRAPHICS_Type struct {
|
||||
// Mosaic control
|
||||
MOSAIC volatile.Register32
|
||||
|
||||
// Alpha control
|
||||
BLDCNT volatile.Register16
|
||||
|
||||
// Fade level
|
||||
BLDALPHA volatile.Register16
|
||||
|
||||
// Blend levels
|
||||
BLDY volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND1_Type struct {
|
||||
// Sweep register
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// Duty/Len/Envelope
|
||||
CNT_H volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND2_Type struct {
|
||||
// Duty/Len/Envelope
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// not used
|
||||
_ volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND3_Type struct {
|
||||
// Stop/Wave RAM select
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// Length/Volume
|
||||
CNT_H volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND4_Type struct {
|
||||
// Length/Envelope
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// not used
|
||||
_ volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND_Type struct {
|
||||
// Control Stereo/Volume/Enable
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// Control Mixing/DMA Control
|
||||
CNT_H volatile.Register16
|
||||
|
||||
// Control Sound on/off
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
// DMA
|
||||
type DMA_Type struct {
|
||||
SAD_L volatile.Register16
|
||||
SAD_H volatile.Register16
|
||||
DAD_L volatile.Register16
|
||||
DAD_H volatile.Register16
|
||||
CNT_L volatile.Register16
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
|
||||
// TIMER
|
||||
type TIMER_Type struct {
|
||||
DATA volatile.Register16
|
||||
CNT volatile.Register16
|
||||
}
|
||||
|
||||
// serial
|
||||
type SIODATA32_Type struct {
|
||||
DATA32_L volatile.Register16
|
||||
DATA32_H volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
CNT volatile.Register16
|
||||
DATA8 volatile.Register16
|
||||
}
|
||||
|
||||
type SIOMULTI_Type struct {
|
||||
MULTI0 volatile.Register16
|
||||
MULTI1 volatile.Register16
|
||||
MULTI2 volatile.Register16
|
||||
MULTI3 volatile.Register16
|
||||
CNT volatile.Register16
|
||||
MLT_SEND volatile.Register16
|
||||
}
|
||||
|
||||
type SIO_Type struct {
|
||||
RCNT volatile.Register16
|
||||
}
|
||||
|
||||
// Keypad registers
|
||||
type KEY_Type struct {
|
||||
INPUT volatile.Register16
|
||||
CNT volatile.Register16
|
||||
}
|
||||
|
||||
// TODO: Joybus communication
|
||||
|
||||
// Interrupt / System registers
|
||||
type INTERRUPT_Type struct {
|
||||
IE volatile.Register16
|
||||
IF volatile.Register16
|
||||
WAITCNT volatile.Register16
|
||||
IME volatile.Register16
|
||||
PAUSE volatile.Register16
|
||||
}
|
||||
|
||||
// LCD OBJ Attributes
|
||||
type OAMOBJ_Type struct {
|
||||
ATT0 volatile.Register16
|
||||
ATT1 volatile.Register16
|
||||
ATT2 volatile.Register16
|
||||
_ volatile.Register16
|
||||
}
|
||||
|
||||
// OAM Rotation/Scaling Parameters
|
||||
type OAMROT_Type struct {
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PA volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PB volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PC volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PD volatile.Register16
|
||||
}
|
||||
|
||||
// Constants for DISP: display
|
||||
const (
|
||||
// BGMODE: background mode.
|
||||
// Position of BGMODE field.
|
||||
DISPCNT_BGMODE_Pos = 0x0
|
||||
// Bit mask of BGMODE field.
|
||||
DISPCNT_BGMODE_Msk = 0x4
|
||||
// BG Mode 0.
|
||||
DISPCNT_BGMODE_0 = 0x0
|
||||
// BG Mode 1.
|
||||
DISPCNT_BGMODE_1 = 0x1
|
||||
// BG Mode 2.
|
||||
DISPCNT_BGMODE_2 = 0x2
|
||||
// BG Mode 3.
|
||||
DISPCNT_BGMODE_3 = 0x3
|
||||
// BG Mode 4.
|
||||
DISPCNT_BGMODE_4 = 0x4
|
||||
|
||||
// FRAMESELECT: frame select (mode 4 and 5 only).
|
||||
DISPCNT_FRAMESELECT_Pos = 0x4
|
||||
DISPCNT_FRAMESELECT_FRAME0 = 0x0
|
||||
DISPCNT_FRAMESELECT_FRAME1 = 0x1
|
||||
|
||||
// HBLANKINTERVAL: 1=Allow access to OAM during H-Blank
|
||||
DISPCNT_HBLANKINTERVAL_Pos = 0x5
|
||||
DISPCNT_HBLANKINTERVAL_NOALLOW = 0x0
|
||||
DISPCNT_HBLANKINTERVAL_ALLOW = 0x1
|
||||
|
||||
// OBJCHARVRAM: (0=Two dimensional, 1=One dimensional)
|
||||
DISPCNT_OBJCHARVRAM_Pos = 0x6
|
||||
DISPCNT_OBJCHARVRAM_2D = 0x0
|
||||
DISPCNT_OBJCHARVRAM_1D = 0x1
|
||||
|
||||
// FORCEDBLANK: (1=Allow FAST access to VRAM,Palette,OAM)
|
||||
DISPCNT_FORCEDBLANK_Pos = 0x7
|
||||
DISPCNT_FORCEDBLANK_NOALLOW = 0x0
|
||||
DISPCNT_FORCEDBLANK_ALLOW = 0x1
|
||||
|
||||
// Screen Display BG0
|
||||
DISPCNT_SCREENDISPLAY_BG0_Pos = 0x8
|
||||
DISPCNT_SCREENDISPLAY_BG0_ENABLE = 0x1
|
||||
DISPCNT_SCREENDISPLAY_BG0_DISABLE = 0x0
|
||||
|
||||
// Screen Display BG1
|
||||
DISPCNT_SCREENDISPLAY_BG1_Pos = 0x9
|
||||
DISPCNT_SCREENDISPLAY_BG1_ENABLE = 0x1
|
||||
DISPCNT_SCREENDISPLAY_BG1_DISABLE = 0x0
|
||||
|
||||
// Screen Display BG2
|
||||
DISPCNT_SCREENDISPLAY_BG2_Pos = 0xA
|
||||
DISPCNT_SCREENDISPLAY_BG2_ENABLE = 0x1
|
||||
DISPCNT_SCREENDISPLAY_BG2_DISABLE = 0x0
|
||||
|
||||
// Screen Display BG3
|
||||
DISPCNT_SCREENDISPLAY_BG3_Pos = 0xB
|
||||
DISPCNT_SCREENDISPLAY_BG3_ENABLE = 0x1
|
||||
DISPCNT_SCREENDISPLAY_BG3_DISABLE = 0x0
|
||||
|
||||
// Screen Display OBJ
|
||||
DISPCNT_SCREENDISPLAY_OBJ_Pos = 0xC
|
||||
DISPCNT_SCREENDISPLAY_OBJ_ENABLE = 0x1
|
||||
DISPCNT_SCREENDISPLAY_OBJ_DISABLE = 0x0
|
||||
|
||||
// Window 0 Display Flag (0=Off, 1=On)
|
||||
DISPCNT_WINDOW0_DISPLAY_Pos = 0xD
|
||||
DISPCNT_WINDOW0_DISPLAY_ENABLE = 0x1
|
||||
DISPCNT_WINDOW0_DISPLAY_DISABLE = 0x0
|
||||
|
||||
// Window 1 Display Flag (0=Off, 1=On)
|
||||
DISPCNT_WINDOW1_DISPLAY_Pos = 0xE
|
||||
DISPCNT_WINDOW1_DISPLAY_ENABLE = 0x1
|
||||
DISPCNT_WINDOW1_DISPLAY_DISABLE = 0x0
|
||||
|
||||
// OBJ Window Display Flag
|
||||
DISPCNT_WINDOWOBJ_DISPLAY_Pos = 0xF
|
||||
DISPCNT_WINDOWOBJ_DISPLAY_ENABLE = 0x1
|
||||
DISPCNT_WINDOWOBJ_DISPLAY_DISABLE = 0x0
|
||||
|
||||
// DISPSTAT: display status.
|
||||
// V-blank
|
||||
DISPSTAT_VBLANK_Pos = 0x0
|
||||
DISPSTAT_VBLANK_ENABLE = 0x1
|
||||
DISPSTAT_VBLANK_DISABLE = 0x0
|
||||
|
||||
// H-blank
|
||||
DISPSTAT_HBLANK_Pos = 0x1
|
||||
DISPSTAT_HBLANK_ENABLE = 0x1
|
||||
DISPSTAT_HBLANK_DISABLE = 0x0
|
||||
|
||||
// V-counter match
|
||||
DISPSTAT_VCOUNTER_Pos = 0x2
|
||||
DISPSTAT_VCOUNTER_MATCH = 0x1
|
||||
DISPSTAT_VCOUNTER_NOMATCH = 0x0
|
||||
|
||||
// V-blank IRQ
|
||||
DISPSTAT_VBLANK_IRQ_Pos = 0x3
|
||||
DISPSTAT_VBLANK_IRQ_ENABLE = 0x1
|
||||
DISPSTAT_VBLANK_IRQ_DISABLE = 0x0
|
||||
|
||||
// H-blank IRQ
|
||||
DISPSTAT_HBLANK_IRQ_Pos = 0x4
|
||||
DISPSTAT_HBLANK_IRQ_ENABLE = 0x1
|
||||
DISPSTAT_HBLANK_IRQ_DISABLE = 0x0
|
||||
|
||||
// V-counter IRQ
|
||||
DISPSTAT_VCOUNTER_IRQ_Pos = 0x5
|
||||
DISPSTAT_VCOUNTER_IRQ_ENABLE = 0x1
|
||||
DISPSTAT_VCOUNTER_IRQ_DISABLE = 0x0
|
||||
|
||||
// V-count setting
|
||||
DISPSTAT_VCOUNT_SETTING_Pos = 0x8
|
||||
)
|
||||
|
||||
const (
|
||||
BGCNT_PRIORITY_Pos = 0x0
|
||||
BGCNT_PRIORITY_Msk = 0x3
|
||||
|
||||
BGCNT_CHAR_BASE_Pos = 0x2
|
||||
BGCNT_CHAR_BASE_Msk = 0x3
|
||||
|
||||
BGCNT_MOSAIC_Pos = 0x6
|
||||
BGCNT_MOSAIC_DISABLE = 0x0
|
||||
BGCNT_MOSAIC_ENABLE = 0x1
|
||||
|
||||
BGCNT_COLORS_Pos = 0x7
|
||||
BGCNT_COLORS_16 = 0x0
|
||||
BGCNT_COLORS_256 = 0x1
|
||||
|
||||
BGCNT_BASE_Pos = 0x8
|
||||
BGCNT_BASE_Msk = 0x1F
|
||||
|
||||
BGCNT_OVERFLOW_Pos = 0xD
|
||||
BGCNT_OVERFLOW_TRANS = 0x0
|
||||
BGCNT_OVERFLOW_WRAP = 0x1
|
||||
|
||||
BGCNT_SIZE_Pos = 0xE
|
||||
BGCNT_SIZE_Msk = 0x3
|
||||
)
|
||||
|
||||
const (
|
||||
BG_HOFS_Pos = 0x0
|
||||
BG_HOFS_Msk = 0x1FF
|
||||
|
||||
BG_VOFS_Pos = 0x0
|
||||
BG_VOFS_Msk = 0x1FF
|
||||
)
|
||||
|
||||
// Constants for TIMER
|
||||
const (
|
||||
// PRESCALER: Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)
|
||||
// Position of PRESCALER field.
|
||||
TIMERCNT_PRESCALER_Pos = 0x0
|
||||
// Bit mask of PRESCALER field.
|
||||
TIMERCNT_PRESCALER_Msk = 0x2
|
||||
// 0=F/1
|
||||
TIMERCNT_PRESCALER_1 = 0x0
|
||||
// 1=F/64
|
||||
TIMERCNT_PRESCALER_64 = 0x1
|
||||
// 2=F/256
|
||||
TIMERCNT_PRESCALER_256 = 0x2
|
||||
// F/1024
|
||||
TIMERCNT_PRESCALER_1024 = 0x3
|
||||
|
||||
// COUNTUP: Count-up Timing (0=Normal, 1=See below) ;Not used in TM0CNT_H
|
||||
// Position of COUNTUP_TIMING field.
|
||||
TIMERCNT_COUNTUP_TIMING_Pos = 0x2
|
||||
TIMERCNT_COUNTUP_TIMING_NORMAL = 0x0
|
||||
TIMERCNT_COUNTUP_TIMING_ENABLED = 0x1
|
||||
|
||||
TIMERCNT_TIMER_IRQ_ENABLED_Pos = 0x06
|
||||
TIMERCNT_TIMER_IRQ_ENABLED = 0x01
|
||||
TIMERCNT_TIMER_IRQ_DISABLED = 0x00
|
||||
|
||||
TIMERCNT_TIMER_STARTSTOP_Pos = 0x07
|
||||
TIMERCNT_TIMER_START = 0x1
|
||||
TIMERCNT_TIMER_STOP = 0x0
|
||||
)
|
||||
|
||||
const (
|
||||
// normal mode
|
||||
SIOCNT_NORMAL_SC_Pos = 0x0
|
||||
SIOCNT_NORMAL_SC_INTERNAL = 0x1
|
||||
SIOCNT_NORMAL_SC_EXTERNAL = 0x0
|
||||
|
||||
SIOCNT_NORMAL_SCSPEED_Pos = 0x1
|
||||
SIOCNT_NORMAL_SCSPEED_256K = 0x0
|
||||
SIOCNT_NORMAL_SCSPEED_2M = 0x1
|
||||
|
||||
SIOCNT_NORMAL_SCSTATE_Pos = 0x2
|
||||
SIOCNT_NORMAL_SCSTATE_LOW = 0x0
|
||||
SIOCNT_NORMAL_SCSTATE_HIGH = 0x1
|
||||
|
||||
SIOCNT_NORMAL_SO_INACTIVE_Pos = 0x3
|
||||
SIOCNT_NORMAL_SO_INACTIVE_LOW = 0x0
|
||||
SIOCNT_NORMAL_SO_INACTIVE_HIGH = 0x1
|
||||
|
||||
SIOCNT_NORMAL_START_Pos = 0x7
|
||||
SIOCNT_NORMAL_START_READY = 0x0
|
||||
SIOCNT_NORMAL_START_ACTIVE = 0x1
|
||||
|
||||
SIOCNT_NORMAL_LEN_Pos = 0xC
|
||||
SIOCNT_NORMAL_LEN8 = 0x0
|
||||
SIOCNT_NORMAL_LEN32 = 0x1
|
||||
|
||||
SIOCNT_NORMAL_MODE_Pos = 0xD
|
||||
SIOCNT_NORMAL_MODE = 0x0
|
||||
|
||||
// multiplayer mode
|
||||
SIOCNT_MULTI_BR_Pos = 0x0
|
||||
SIOCNT_MULTI_BR_Msk = 0x3
|
||||
SIOCNT_MULTI_BR_9600 = 0x0
|
||||
SIOCNT_MULTI_BR_38400 = 0x1
|
||||
SIOCNT_MULTI_BR_57600 = 0x2
|
||||
SIOCNT_MULTI_BR_115200 = 0x3
|
||||
|
||||
SIOCNT_MULTI_SI_Pos = 0x2
|
||||
SIOCNT_MULTI_SI_PARENT = 0x0
|
||||
SIOCNT_MULTI_SI_CHILD = 0x1
|
||||
|
||||
SIOCNT_MULTI_SD_Pos = 0x3
|
||||
SIOCNT_MULTI_SD_BAD = 0x0
|
||||
SIOCNT_MULTI_SD_READY = 0x1
|
||||
|
||||
SIOCNT_MULTI_ID_Pos = 0x4
|
||||
SIOCNT_MULTI_ID_Msk = 0x3
|
||||
SIOCNT_MULTI_ID_PARENT = 0x0
|
||||
SIOCNT_MULTI_ID_CHILD1 = 0x1
|
||||
SIOCNT_MULTI_ID_CHILD2 = 0x2
|
||||
SIOCNT_MULTI_ID_CHILD3 = 0x3
|
||||
|
||||
SIOCNT_MULTI_ERR_Pos = 0x6
|
||||
SIOCNT_MULTI_ERR_NORMAL = 0x0
|
||||
SIOCNT_MULTI_ERR_ERROR = 0x1
|
||||
|
||||
SIOCNT_MULTI_STARTBUSY_Pos = 0x7
|
||||
SIOCNT_MULTI_STARTBUSY_INACTIVE = 0x0
|
||||
SIOCNT_MULTI_STARTBUSY_STARTBUSY = 0x1
|
||||
|
||||
SIOCNT_MULTI_MODE_Pos = 0xC
|
||||
SIOCNT_MULTI_MODE_Msk = 0x3
|
||||
SIOCNT_MULTI_MODE = 0x01
|
||||
|
||||
// uart mode
|
||||
SIOCNT_UART_BR_Pos = 0x0
|
||||
SIOCNT_UART_BR_Msk = 0x3
|
||||
SIOCNT_UART_BR_9600 = 0x0
|
||||
SIOCNT_UART_BR_38400 = 0x1
|
||||
SIOCNT_UART_BR_57600 = 0x2
|
||||
SIOCNT_UART_BR_115200 = 0x3
|
||||
|
||||
SIOCNT_UART_CTS_Pos = 0x2
|
||||
SIOCNT_UART_CTS_ALWAYS = 0x0
|
||||
SIOCNT_UART_CTS_SENDLOW = 0x1
|
||||
|
||||
SIOCNT_UART_PARITY_Pos = 0x3
|
||||
SIOCNT_UART_PARITY_EVEN = 0x0
|
||||
SIOCNT_UART_PARITY_ODD = 0x1
|
||||
|
||||
SIOCNT_UART_SEND_Pos = 0x4
|
||||
SIOCNT_UART_SEND_NOTFULL = 0x0
|
||||
SIOCNT_UART_SEND_FULL = 0x1
|
||||
|
||||
SIOCNT_UART_REC_Pos = 0x5
|
||||
SIOCNT_UART_REC_NOTEMPTY = 0x0
|
||||
SIOCNT_UART_REC_EMPTY = 0x1
|
||||
|
||||
SIOCNT_UART_ERR_Pos = 0x6
|
||||
SIOCNT_UART_ERR_NOERROR = 0x0
|
||||
SIOCNT_UART_ERR_ERROR = 0x1
|
||||
|
||||
SIOCNT_UART_DATALEN_Pos = 0x7
|
||||
SIOCNT_UART_DATALEN_7 = 0x0
|
||||
SIOCNT_UART_DATALEN_8 = 0x1
|
||||
|
||||
SIOCNT_UART_FIFO_Pos = 0x8
|
||||
SIOCNT_UART_FIFO_DISABLE = 0x0
|
||||
SIOCNT_UART_FIFO_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_PARITY_ENABLE_Pos = 0x9
|
||||
SIOCNT_UART_PARITY_DISABLE = 0x0
|
||||
SIOCNT_UART_PARITY_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_SEND_ENABLE_Pos = 0xA
|
||||
SIOCNT_UART_SEND_DISABLE = 0x0
|
||||
SIOCNT_UART_SEND_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_REC_ENABLE_Pos = 0xB
|
||||
SIOCNT_UART_REC_DISABLE = 0x0
|
||||
SIOCNT_UART_REC_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_MODE_Pos = 0xC
|
||||
SIOCNT_UART_MODE_Msk = 0x3
|
||||
SIOCNT_UART_MODE = 0x11
|
||||
|
||||
// IRQs used by all
|
||||
SIOCNT_IRQ_Pos = 0xE
|
||||
SIOCNT_IRQ_DISABLE = 0x0
|
||||
SIOCNT_IRQ_ENABLE = 0x1
|
||||
)
|
||||
|
||||
const (
|
||||
SIO_RCNT_MODE_Pos = 0xF
|
||||
SIO_RCNT_MODE_NORMAL = 0x0
|
||||
SIO_RCNT_MODE_MULTI = 0x0
|
||||
SIO_RCNT_MODE_UART = 0x0
|
||||
)
|
||||
|
||||
// Constants for KEY
|
||||
const (
|
||||
// KEYINPUT
|
||||
KEYINPUT_PRESSED = 0x0
|
||||
KEYINPUT_RELEASED = 0x1
|
||||
KEYINPUT_BUTTON_A_Pos = 0x0
|
||||
KEYINPUT_BUTTON_B_Pos = 0x1
|
||||
KEYINPUT_BUTTON_SELECT_Pos = 0x2
|
||||
KEYINPUT_BUTTON_START_Pos = 0x3
|
||||
KEYINPUT_BUTTON_RIGHT_Pos = 0x4
|
||||
KEYINPUT_BUTTON_LEFT_Pos = 0x5
|
||||
KEYINPUT_BUTTON_UP_Pos = 0x6
|
||||
KEYINPUT_BUTTON_DOWN_Pos = 0x7
|
||||
KEYINPUT_BUTTON_R_Pos = 0x8
|
||||
KEYINPUT_BUTTON_L_Pos = 0x9
|
||||
|
||||
// KEYCNT
|
||||
KEYCNT_IGNORE = 0x0
|
||||
KEYCNT_SELECT = 0x1
|
||||
KEYCNT_BUTTON_A_Pos = 0x0
|
||||
KEYCNT_BUTTON_B_Pos = 0x1
|
||||
KEYCNT_BUTTON_SELECT_Pos = 0x2
|
||||
KEYCNT_BUTTON_START_Pos = 0x3
|
||||
KEYCNT_BUTTON_RIGHT_Pos = 0x4
|
||||
KEYCNT_BUTTON_LEFT_Pos = 0x5
|
||||
KEYCNT_BUTTON_UP_Pos = 0x6
|
||||
KEYCNT_BUTTON_DOWN_Pos = 0x7
|
||||
KEYCNT_BUTTON_R_Pos = 0x8
|
||||
KEYCNT_BUTTON_L_Pos = 0x9
|
||||
KEYCNT_BUTTON_IRQ_DISABLE = 0x0
|
||||
KEYCNT_BUTTON_IRQ_ENABLE = 0x1
|
||||
KEYCNT_BUTTON_IRQ_ENABLE_Pos = 0xE
|
||||
KEYCNT_BUTTON_IRQ_COND_OR = 0x0
|
||||
KEYCNT_BUTTON_IRQ_COND_AND = 0x1
|
||||
KEYCNT_BUTTON_IRQ_COND_Pos = 0xF
|
||||
)
|
||||
|
||||
// Constants for INTERRUPT
|
||||
const (
|
||||
// IE
|
||||
INTERRUPT_IE_ENABLED = 0x1
|
||||
INTERRUPT_IE_DISABLED = 0x0
|
||||
INTERRUPT_IE_VBLANK_Pos = 0x0
|
||||
INTERRUPT_IE_HBLANK_Pos = 0x1
|
||||
INTERRUPT_IE_VCOUNTER_MATCH_Pos = 0x2
|
||||
INTERRUPT_IE_TIMER0_OVERFLOW_Pos = 0x3
|
||||
INTERRUPT_IE_TIMER1_OVERFLOW_Pos = 0x4
|
||||
INTERRUPT_IE_TIMER2_OVERFLOW_Pos = 0x5
|
||||
INTERRUPT_IE_TIMER3_OVERFLOW_Pos = 0x6
|
||||
INTERRUPT_IE_SERIAL_Pos = 0x7
|
||||
INTERRUPT_IE_DMA0_Pos = 0x8
|
||||
INTERRUPT_IE_DMA1_Pos = 0x9
|
||||
INTERRUPT_IE_DMA2_Pos = 0xA
|
||||
INTERRUPT_IE_DMA3_Pos = 0xB
|
||||
INTERRUPT_IE_KEYPAD_Pos = 0xC
|
||||
INTERRUPT_IE_GAMPAK_Pos = 0xD
|
||||
|
||||
// IF
|
||||
INTERRUPT_IF_ENABLED = 0x1
|
||||
INTERRUPT_IF_DISABLED = 0x0
|
||||
INTERRUPT_IF_VBLANK_Pos = 0x0
|
||||
INTERRUPT_IF_HBLANK_Pos = 0x1
|
||||
INTERRUPT_IF_VCOUNTER_MATCH_Pos = 0x2
|
||||
INTERRUPT_IF_TIMER0_OVERFLOW_Pos = 0x3
|
||||
INTERRUPT_IF_TIMER1_OVERFLOW_Pos = 0x4
|
||||
INTERRUPT_IF_TIMER2_OVERFLOW_Pos = 0x5
|
||||
INTERRUPT_IF_TIMER3_OVERFLOW_Pos = 0x6
|
||||
INTERRUPT_IF_SERIAL_Pos = 0x7
|
||||
INTERRUPT_IF_DMA0_Pos = 0x8
|
||||
INTERRUPT_IF_DMA1_Pos = 0x9
|
||||
INTERRUPT_IF_DMA2_Pos = 0xA
|
||||
INTERRUPT_IF_DMA3_Pos = 0xB
|
||||
INTERRUPT_IF_KEYPAD_Pos = 0xC
|
||||
INTERRUPT_IF_GAMPAK_Pos = 0xD
|
||||
)
|
||||
|
||||
const (
|
||||
OAMOBJ_ATT0_Y_Pos = 0x0
|
||||
OAMOBJ_ATT0_Y_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT0_OM_Pos = 0x8
|
||||
OAMOBJ_ATT0_OM_Msk = 0x3
|
||||
OAMOBJ_ATT0_OM_REG = 0x0
|
||||
OAMOBJ_ATT0_OM_AFF = 0x1
|
||||
OAMOBJ_ATT0_OM_HIDE = 0x2
|
||||
OAMOBJ_ATT0_OM_DBL = 0x3
|
||||
|
||||
OAMOBJ_ATT0_GM_Pos = 0xA
|
||||
OAMOBJ_ATT0_GM_Msk = 0x3
|
||||
OAMOBJ_ATT0_GM_REG = 0x0
|
||||
OAMOBJ_ATT0_GM_BLEND = 0x1
|
||||
OAMOBJ_ATT0_GM_WIN = 0x2
|
||||
|
||||
OAMOBJ_ATT0_MOSAIC_Pos = 0xC
|
||||
OAMOBJ_ATT0_MOSAIC_DISABLE = 0x0
|
||||
OAMOBJ_ATT0_MOSAIC_ENABLE = 0x1
|
||||
|
||||
OAMOBJ_ATT0_COLOR_Pos = 0xD
|
||||
OAMOBJ_ATT0_COLOR_4BPP = 0x0
|
||||
OAMOBJ_ATT0_COLOR_8BPP = 0x1
|
||||
|
||||
OAMOBJ_ATT0_SH_Pos = 0xE
|
||||
OAMOBJ_ATT0_SH_Msk = 0x3
|
||||
OAMOBJ_ATT0_SH_SQUARE = 0x0
|
||||
OAMOBJ_ATT0_SH_WIDE = 0x1
|
||||
OAMOBJ_ATT0_SH_TALL = 0x2
|
||||
|
||||
OAMOBJ_ATT1_X_Pos = 0x0
|
||||
OAMOBJ_ATT1_X_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT1_AID_Pos = 0x9
|
||||
OAMOBJ_ATT1_AID_Msk = 0x1F
|
||||
|
||||
OAMOBJ_ATT1_HF_Pos = 0xC
|
||||
OAMOBJ_ATT1_HF_NOFLIP = 0x0
|
||||
OAMOBJ_ATT1_HF_FLIP = 0x1
|
||||
|
||||
OAMOBJ_ATT1_VF_Pos = 0xD
|
||||
OAMOBJ_ATT1_VF_NOFLIP = 0x0
|
||||
OAMOBJ_ATT1_VF_FLIP = 0x1
|
||||
|
||||
OAMOBJ_ATT1_SZ_Pos = 0xE
|
||||
OAMOBJ_ATT1_SZ_Msk = 0x3
|
||||
|
||||
OAMOBJ_ATT2_TID_Pos = 0x0
|
||||
OAMOBJ_ATT2_TID_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT2_PR_Pos = 0xA
|
||||
OAMOBJ_ATT2_PR_Msk = 0x3
|
||||
|
||||
OAMOBJ_ATT2_PB_Pos = 0xC
|
||||
OAMOBJ_ATT2_PB_Msk = 0xF
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// This is used for smoke tests for chips without an associated board.
|
||||
|
||||
func main() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
+38
-11
@@ -7,7 +7,10 @@ import (
|
||||
|
||||
var (
|
||||
err error
|
||||
message = "1234567887654321123456788765432112345678876543211234567887654321"
|
||||
message = "1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -21,30 +24,54 @@ func main() {
|
||||
println("Flash erase block size:", machine.Flash.EraseBlockSize())
|
||||
println()
|
||||
|
||||
flash := machine.OpenFlashBuffer(machine.Flash, machine.FlashDataStart())
|
||||
original := make([]byte, len(message))
|
||||
saved := make([]byte, len(message))
|
||||
|
||||
// Read flash contents on start (data shall survive power off)
|
||||
print("Reading data from flash: ")
|
||||
_, err = flash.Read(original)
|
||||
println("Reading original data from flash:")
|
||||
_, err = machine.Flash.ReadAt(original, 0)
|
||||
checkError(err)
|
||||
println(string(original))
|
||||
|
||||
// erase flash
|
||||
println("Erasing flash...")
|
||||
needed := int64(len(message)) / machine.Flash.EraseBlockSize()
|
||||
if needed == 0 {
|
||||
// have to erase at least 1 block
|
||||
needed = 1
|
||||
}
|
||||
|
||||
err := machine.Flash.EraseBlocks(0, needed)
|
||||
checkError(err)
|
||||
|
||||
// Write the message to flash
|
||||
print("Writing data to flash: ")
|
||||
flash.Seek(0, 0) // rewind back to beginning
|
||||
_, err = flash.Write([]byte(message))
|
||||
println("Writing new data to flash:")
|
||||
_, err = machine.Flash.WriteAt([]byte(message), 0)
|
||||
checkError(err)
|
||||
println(string(message))
|
||||
|
||||
// Read back flash contents after write (verify data is the same as written)
|
||||
print("Reading data back from flash: ")
|
||||
flash.Seek(0, 0) // rewind back to beginning
|
||||
_, err = flash.Read(saved)
|
||||
println("Reading data back from flash: ")
|
||||
_, err = machine.Flash.ReadAt(saved, 0)
|
||||
checkError(err)
|
||||
if !equal(saved, []byte(message)) {
|
||||
println("data verify error")
|
||||
}
|
||||
|
||||
println(string(saved))
|
||||
println()
|
||||
println("Done.")
|
||||
}
|
||||
|
||||
func equal(a, b []byte) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"machine/usb/joystick"
|
||||
"machine/usb/hid/joystick"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
// to override the USB Manufacturer or Product names:
|
||||
//
|
||||
// tinygo flash -target circuitplay-express -ldflags="-X main.usbManufacturer='TinyGopher Labs' -X main.usbProduct='GopherKeyboard'" examples/hid-keyboard
|
||||
//
|
||||
// you can also override the VID/PID. however, only set this if you know what you are doing,
|
||||
// since changing it can make it difficult to reflash some devices.
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"machine/usb"
|
||||
"machine/usb/hid/keyboard"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var usbVID, usbPID string
|
||||
var usbManufacturer, usbProduct string
|
||||
|
||||
func main() {
|
||||
button := machine.BUTTON
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
@@ -19,3 +30,23 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if usbVID != "" {
|
||||
vid, _ := strconv.ParseUint(usbVID, 0, 16)
|
||||
usb.VendorID = uint16(vid)
|
||||
}
|
||||
|
||||
if usbPID != "" {
|
||||
pid, _ := strconv.ParseUint(usbPID, 0, 16)
|
||||
usb.ProductID = uint16(pid)
|
||||
}
|
||||
|
||||
if usbManufacturer != "" {
|
||||
usb.Manufacturer = usbManufacturer
|
||||
}
|
||||
|
||||
if usbProduct != "" {
|
||||
usb.Product = usbProduct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Example demonstrating I2C controller / target comms.
|
||||
//
|
||||
// To use this example, physically connect I2C0 and I2C1.
|
||||
// I2C0 will be used as the controller and I2C1 used as
|
||||
// the target.
|
||||
//
|
||||
// In this example, the target implements a simple memory
|
||||
// map, with the controller able to read and write the
|
||||
// memory.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
targetAddress = 0x11
|
||||
maxTxSize = 16
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Delay to enable USB monitor time to attach
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Controller uses default I2C pins and controller
|
||||
// mode is default
|
||||
err := controller.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
panic("failed to config I2C0 as controller")
|
||||
}
|
||||
|
||||
// Target uses alternate pins and target mode is
|
||||
// explicit
|
||||
err = target.Configure(machine.I2CConfig{
|
||||
Mode: machine.I2CModeTarget,
|
||||
SCL: TARGET_SCL,
|
||||
SDA: TARGET_SDA,
|
||||
})
|
||||
if err != nil {
|
||||
panic("failed to config I2C1 as target")
|
||||
}
|
||||
|
||||
// Put welcome message directly into target memory
|
||||
copy(mem[0:], []byte("Hello World!"))
|
||||
err = target.Listen(targetAddress)
|
||||
if err != nil {
|
||||
panic("failed to listen as I2C target")
|
||||
}
|
||||
|
||||
// Start the target
|
||||
go targetMain()
|
||||
|
||||
// Read welcome message from target over I2C
|
||||
buf := make([]byte, 12)
|
||||
err = controller.Tx(targetAddress, []byte{0}, buf)
|
||||
if err != nil {
|
||||
println("failed to read welcome message over I2C")
|
||||
panic(err)
|
||||
}
|
||||
println("message from target:", string(buf))
|
||||
|
||||
// Write (1,2,3) to the target starting at memory address 3
|
||||
println("writing (1,2,3) @ 0x3")
|
||||
err = controller.Tx(targetAddress, []byte{3, 1, 2, 3}, nil)
|
||||
if err != nil {
|
||||
println("failed to write to I2C target")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond) // Wait for target to process write
|
||||
println("mem:", mem[0], mem[1], mem[2], mem[3], mem[4], mem[5])
|
||||
|
||||
// Read memory address 4 from target, which should be the value 2
|
||||
buf = make([]byte, 1)
|
||||
err = controller.Tx(targetAddress, []byte{4}, buf[:1])
|
||||
if err != nil {
|
||||
println("failed to read from I2C target")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if buf[0] != 2 {
|
||||
panic("read incorrect value from I2C target")
|
||||
}
|
||||
|
||||
println("all done!")
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// -- target ---
|
||||
|
||||
var (
|
||||
mem [256]byte
|
||||
)
|
||||
|
||||
// targetMain implements the 'main loop' for an I2C target
|
||||
func targetMain() {
|
||||
buf := make([]byte, maxTxSize)
|
||||
var ptr uint8
|
||||
|
||||
for {
|
||||
evt, n, err := target.WaitForEvent(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch evt {
|
||||
case machine.I2CReceive:
|
||||
if n > 0 {
|
||||
ptr = buf[0]
|
||||
}
|
||||
|
||||
for o := 1; o < n; o++ {
|
||||
mem[ptr] = buf[o]
|
||||
ptr++
|
||||
}
|
||||
|
||||
case machine.I2CRequest:
|
||||
target.Reply(mem[ptr:256])
|
||||
|
||||
case machine.I2CFinish:
|
||||
// nothing to do
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build feather_nrf52840
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
TARGET_SCL = machine.A5
|
||||
TARGET_SDA = machine.A4
|
||||
)
|
||||
|
||||
var (
|
||||
controller = machine.I2C0
|
||||
target = machine.I2C1
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build rp2040
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
TARGET_SCL = machine.GPIO25
|
||||
TARGET_SDA = machine.GPIO24
|
||||
)
|
||||
|
||||
var (
|
||||
controller = machine.I2C1
|
||||
target = machine.I2C0
|
||||
)
|
||||
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
|
||||
// This example demonstrates how to use go:section to place code into RAM for
|
||||
// execution. The code is present in flash in the `.data` region and copied
|
||||
// into the correct place in RAM early in startup sequence (at the same time
|
||||
// as non-zero global variables are initialized).
|
||||
//
|
||||
// This example should work on any ARM Cortex MCU.
|
||||
//
|
||||
// For Go code use the pragma "//go:section", for cgo use the "section" and
|
||||
// "noinline" attributes. The `.ramfuncs` section is explicitly placed into
|
||||
// the `.data` region by the linker script.
|
||||
//
|
||||
// Running the example should print out the program counter from the functions
|
||||
// below. The program counters should be in different memory regions.
|
||||
//
|
||||
// On RP2040, for example, the output is something like this:
|
||||
//
|
||||
// Go in RAM: 0x20000DB4
|
||||
// Go in flash: 0x10007610
|
||||
// cgo in RAM: 0x20000DB8
|
||||
// cgo in flash: 0x10002C26
|
||||
//
|
||||
// This can be confirmed using `objdump -t xxx.elf | grep main | sort`:
|
||||
//
|
||||
// 00000000 l df *ABS* 00000000 main
|
||||
// 1000760d l F .text 00000004 main.in_flash
|
||||
// 10007611 l F .text 0000000c __Thumbv6MABSLongThunk_main.in_ram
|
||||
// 1000761d l F .text 0000000c __Thumbv6MABSLongThunk__Cgo_static_eea7585d7291176ad3bb_main_c_in_ram
|
||||
// 1000bdb5 l O .text 00000013 main$string
|
||||
// 1000bdc8 l O .text 00000013 main$string.1
|
||||
// 1000bddb l O .text 00000013 main$string.2
|
||||
// 1000bdee l O .text 00000013 main$string.3
|
||||
// 20000db1 l F .data 00000004 main.in_ram
|
||||
// 20000db5 l F .data 00000004 _Cgo_static_eea7585d7291176ad3bb_main_c_in_ram
|
||||
//
|
||||
|
||||
import (
|
||||
"device"
|
||||
"fmt"
|
||||
"time"
|
||||
_ "unsafe" // unsafe is required for "//go:section"
|
||||
)
|
||||
|
||||
/*
|
||||
#define ram_func __attribute__((section(".ramfuncs"),noinline))
|
||||
|
||||
static ram_func void* main_c_in_ram() {
|
||||
void* p = 0;
|
||||
|
||||
asm(
|
||||
"MOV %0, PC"
|
||||
: "=r"(p)
|
||||
);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void* main_c_in_flash() {
|
||||
void* p = 0;
|
||||
|
||||
asm(
|
||||
"MOV %0, PC"
|
||||
: "=r"(p)
|
||||
);
|
||||
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
fmt.Printf("Go in RAM: 0x%X\n", in_ram())
|
||||
fmt.Printf("Go in flash: 0x%X\n", in_flash())
|
||||
fmt.Printf("cgo in RAM: 0x%X\n", C.main_c_in_ram())
|
||||
fmt.Printf("cgo in flash: 0x%X\n", C.main_c_in_flash())
|
||||
}
|
||||
|
||||
//go:section .ramfuncs
|
||||
func in_ram() uintptr {
|
||||
return device.AsmFull("MOV {}, PC", nil)
|
||||
}
|
||||
|
||||
// 'go:noinline' used here to prevent function being 'inlined' into main()
|
||||
// so it appears in objdump output. In normal use, go:inline is not
|
||||
// required for functions running from flash (flash is the default).
|
||||
//
|
||||
//go:noinline
|
||||
func in_flash() uintptr {
|
||||
return device.AsmFull("MOV {}, PC", nil)
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"machine/usb/midi"
|
||||
"machine/usb/adc/midi"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -15,12 +15,11 @@ func main() {
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
button := machine.BUTTON
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
|
||||
m := midi.Port()
|
||||
m.SetHandler(func(b []byte) {
|
||||
led.Set(!led.Get())
|
||||
fmt.Printf("% X\r\n", b)
|
||||
m.Write(b)
|
||||
})
|
||||
|
||||
|
||||
@@ -114,9 +114,9 @@ tinygo_swapTask:
|
||||
pop {r4-r11, pc}
|
||||
#else
|
||||
pop {r4-r7}
|
||||
.cfi_def_cfa_offset 5*9
|
||||
.cfi_def_cfa_offset 5*4
|
||||
pop {r0-r3}
|
||||
.cfi_def_cfa_offset 1*9
|
||||
.cfi_def_cfa_offset 1*4
|
||||
mov r8, r0
|
||||
mov r9, r1
|
||||
mov r10, r2
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//go:build scheduler.tasks && cortexm
|
||||
#include <stdint.h>
|
||||
|
||||
uintptr_t SystemStack() {
|
||||
uintptr_t sp;
|
||||
asm volatile(
|
||||
"mrs %0, MSP"
|
||||
: "=r"(sp)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return sp;
|
||||
}
|
||||
@@ -8,8 +8,8 @@ package task
|
||||
// PSP, which is used for goroutines) so that goroutines do not need extra stack
|
||||
// space for interrupts.
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"device/arm"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -67,6 +67,6 @@ func (s *state) pause() {
|
||||
|
||||
// SystemStack returns the system stack pointer. On Cortex-M, it is always
|
||||
// available.
|
||||
func SystemStack() uintptr {
|
||||
return arm.AsmFull("mrs {}, MSP", nil)
|
||||
}
|
||||
//
|
||||
//export SystemStack
|
||||
func SystemStack() uintptr
|
||||
|
||||
@@ -9,4 +9,5 @@ type ADCConfig struct {
|
||||
Reference uint32 // analog reference voltage (AREF) in millivolts
|
||||
Resolution uint32 // number of bits for a single conversion (e.g., 8, 10, 12)
|
||||
Samples uint32 // number of samples for a single conversion (e.g., 4, 8, 16, 32)
|
||||
SampleTime uint32 // sample time, in microseconds (µs)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//go:build bluemicro840
|
||||
|
||||
package machine
|
||||
|
||||
const HasLowFrequencyCrystal = true
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
D006 = P0_06
|
||||
D008 = P0_08
|
||||
D015 = P0_15
|
||||
D017 = P0_17
|
||||
D020 = P0_20
|
||||
D013 = P0_13
|
||||
D024 = P0_24
|
||||
D009 = P0_09
|
||||
D010 = P0_10
|
||||
D106 = P1_06
|
||||
|
||||
D031 = P0_31 // AIN7; P0.31 (AIN7) is used to read the voltage of the battery via ADC. It can’t be used for any other function.
|
||||
D012 = P0_12 // VCC 3.3V; P0.12 on VCC shuts off the power to VCC when you set it to high; This saves on battery immensely for LEDs of all kinds that eat power even when off
|
||||
|
||||
D030 = P0_30
|
||||
D026 = P0_26
|
||||
D029 = P0_29
|
||||
D002 = P0_02
|
||||
D113 = P1_13
|
||||
D003 = P0_03
|
||||
D028 = P0_28
|
||||
D111 = P1_11
|
||||
)
|
||||
|
||||
// Analog Pins
|
||||
const (
|
||||
AIN0 = P0_02
|
||||
AIN1 = P0_03
|
||||
AIN2 = P0_04 // Not Connected
|
||||
AIN3 = P0_05 // Not Connected
|
||||
AIN4 = P0_28
|
||||
AIN5 = P0_29
|
||||
AIN6 = P0_30
|
||||
AIN7 = P0_31 // Battery
|
||||
)
|
||||
|
||||
const (
|
||||
LED1 Pin = P1_04 // Red LED
|
||||
LED2 Pin = P1_10 // Blue LED
|
||||
LED Pin = LED1
|
||||
)
|
||||
|
||||
// UART0 pins (logical UART1) - Maps to same location as Pro Micro
|
||||
const (
|
||||
UART_RX_PIN = P0_08
|
||||
UART_TX_PIN = P0_06
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = P0_15 // I2C0 external
|
||||
SCL_PIN = P0_17 // I2C0 external
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = P1_13 // SCK
|
||||
SPI0_SDI_PIN = P0_03 // SDI
|
||||
SPI0_SDO_PIN = P0_28 // SDO
|
||||
|
||||
)
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "bluemicro840"
|
||||
usb_STRING_MANUFACTURER = "BlueMicro"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x1d50
|
||||
usb_PID uint16 = 0x6161
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user