mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-27 07:08:42 +00:00
Compare commits
351 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6645f412ae | |||
| 35a61ac8c5 | |||
| c1a4ed1489 | |||
| 140c82e012 | |||
| dc23ce73d6 | |||
| e039ce131c | |||
| d59c706e60 | |||
| 26d3645317 | |||
| 432ebe13ed | |||
| 16eefc59eb | |||
| fb1bf2e6bf | |||
| 0922e3e956 | |||
| bd61913973 | |||
| 2dbfdbae10 | |||
| 05029c4fb5 | |||
| a7b30639d8 | |||
| 4adc661197 | |||
| 311c071ae6 | |||
| f1fdfe2313 | |||
| 7c3dc05117 | |||
| e569dcfe38 | |||
| 20038817ae | |||
| 9ce73cfafa | |||
| 0033c23848 | |||
| 5c15a68d18 | |||
| 02384c9414 | |||
| e79edb58b2 | |||
| bf80e9b446 | |||
| 30355cec9f | |||
| 9111927f85 | |||
| 10224a4bf8 | |||
| 33ddee76db | |||
| 7fa50a55cf | |||
| 1c0c26b8b7 | |||
| 3abe58448b | |||
| 364ac2dcb2 | |||
| e111b489ec | |||
| f31b39775f | |||
| 6c30583062 | |||
| d29e8e5f22 | |||
| a93640662e | |||
| 3fb0a90854 | |||
| df09dbdf0f | |||
| 134de98ba5 | |||
| 221ea6a54c | |||
| 7ffbcbc666 | |||
| 5f66260c3a | |||
| ba95eb3e1b | |||
| f16697624d | |||
| cb311ed25e | |||
| 6f686d12af | |||
| 6a0acfc735 | |||
| 27f8ec17fc | |||
| a683881eb7 | |||
| 335b085fd2 | |||
| 11c2b76e29 | |||
| 6605b6e43f | |||
| ec18e89365 | |||
| 39cde9f9a3 | |||
| 2747027ef2 | |||
| 4465360f3d | |||
| c33113ab5f | |||
| eab43851ac | |||
| c3f1832d9a | |||
| 2328d1e799 | |||
| 5fabc203db | |||
| d9d19e812e | |||
| 45dd431f19 | |||
| 088a660c00 | |||
| 1ff348fb1f | |||
| cd364a9315 | |||
| ca584de84a | |||
| 594be6db63 | |||
| aef70a5839 | |||
| e6e7250a47 | |||
| 7b3dc19445 | |||
| 8e36d2758b | |||
| 7cbbfd6fc5 | |||
| e8bb38f7c9 | |||
| 1b9bb143bf | |||
| 41f666c670 | |||
| 469e2434fd | |||
| 278aa09819 | |||
| dded832238 | |||
| 8ffabbea64 | |||
| 29b4c6723f | |||
| 039f48f3d2 | |||
| eed4afda63 | |||
| ce888e1042 | |||
| f5d0ec93ef | |||
| 3a0d72457b | |||
| c980e48ad4 | |||
| f5bd750a4d | |||
| 0a5875ab2e | |||
| 54ecf74261 | |||
| 9b83acffe6 | |||
| 67aa15e92e | |||
| 0d6efc6429 | |||
| 1bd3ade825 | |||
| fb8ed8fde8 | |||
| c698eeacba | |||
| 906a20d3bf | |||
| 1be377c47d | |||
| 4dbb5dd4da | |||
| 997974376d | |||
| 7d51044892 | |||
| 37c080083b | |||
| 70a0dee8c8 | |||
| de83d67364 | |||
| 7a5a50d949 | |||
| d348d8b4cf | |||
| 443de9fe1c | |||
| c72f1d5e62 | |||
| ca8fcc9479 | |||
| d01a932201 | |||
| 85d223c5e2 | |||
| 7b486e398a | |||
| da69f18e91 | |||
| 6971b8a69e | |||
| 6682e41ab4 | |||
| 18033ebc36 | |||
| 89d9e33bca | |||
| e80e7e5c10 | |||
| 6233915ecf | |||
| fd8e0bd70b | |||
| 45e2863e9f | |||
| 4204f3d065 | |||
| ddbd65beec | |||
| 1a1506ef79 | |||
| 8793dc37fa | |||
| e9d78a78ea | |||
| 7ec9cfc61c | |||
| 294cf28e43 | |||
| 2f7a66e6d3 | |||
| a4f9c9d1b6 | |||
| aa10b682e4 | |||
| eafbe4ee69 | |||
| cf5912412d | |||
| 1f114b2acf | |||
| 94ebddbdfe | |||
| aa1ca27789 | |||
| 9999320cd0 | |||
| 74429b4a14 | |||
| bcb191c01e | |||
| ddb848816f | |||
| 889911d0a6 | |||
| a4dd38de81 | |||
| 486ee37a40 | |||
| 944176beef | |||
| c396418187 | |||
| 1b4ab772d2 | |||
| aca0fe0412 | |||
| af511c1118 | |||
| 5ba8766cbc | |||
| b792c10680 | |||
| 12d41ba0c1 | |||
| 020cca8c3c | |||
| 4cbd34d32f | |||
| 6426bf79b4 | |||
| aed8116b22 | |||
| f6c759ccbf | |||
| 4b389b90e8 | |||
| 4c3680635e | |||
| 0755145824 | |||
| eabd1ddce0 | |||
| 0e84235f9a | |||
| 894839484c | |||
| 1fadd0e772 | |||
| eba6e7a428 | |||
| f4a6e0373b | |||
| d274545e63 | |||
| f74d25c882 | |||
| 618c689246 | |||
| 9d29971755 | |||
| 451c57af92 | |||
| 59feac28b9 | |||
| c1f48fc79a | |||
| 3c07a36e95 | |||
| 98b3c27c76 | |||
| ddacdfacd5 | |||
| 2d477e069d | |||
| ed1a56785a | |||
| f496571747 | |||
| 17fed5980b | |||
| 2ff04f1a87 | |||
| f763865c5c | |||
| 52edf52245 | |||
| 8161b766d3 | |||
| 709349e24b | |||
| 5fd4878574 | |||
| a24dc8c543 | |||
| c3d514a751 | |||
| 5b7a2c73db | |||
| aaf6a36c55 | |||
| dc6e0e23b9 | |||
| 44b0c79eaf | |||
| 27e5baeb57 | |||
| a6a4f85e61 | |||
| 3386316b9f | |||
| 410bb9c103 | |||
| f176b3a480 | |||
| 9b1a3a2236 | |||
| b29edadf48 | |||
| d04332d688 | |||
| 547288529c | |||
| bd8de8719f | |||
| 2fd44ac341 | |||
| dc30aef687 | |||
| 29cadaa23b | |||
| a7c149f8dc | |||
| c2a04e1a45 | |||
| f748dc6fd8 | |||
| bfc21ad906 | |||
| 41726fab9d | |||
| 82f4fcf2a3 | |||
| 3a00f00f62 | |||
| a71f776203 | |||
| d2f60c02bb | |||
| 7ca53138bc | |||
| a9c0501826 | |||
| 60fb4b95fa | |||
| 323b62b405 | |||
| 40fb3466c1 | |||
| 2333ef2454 | |||
| 0ac7bf8c8b | |||
| 38a3ccee52 | |||
| 47115f0380 | |||
| 1f00425eb3 | |||
| 71245845c8 | |||
| d9f6f3b81f | |||
| b81a7c2bca | |||
| 0ec2f0818a | |||
| 4a6a82ae79 | |||
| b14ee51ff6 | |||
| 394116e998 | |||
| f902437848 | |||
| 86cc3b6c12 | |||
| 6bb6ea2432 | |||
| 3c590e36ad | |||
| 69a4dda8c8 | |||
| 8fbaffe56e | |||
| bfafef8df1 | |||
| 26ff622148 | |||
| 88a68eaf7e | |||
| 46a2a177c1 | |||
| b0ea05a853 | |||
| f3b79c412f | |||
| f4f3ad5051 | |||
| 0757ccc657 | |||
| 47282be619 | |||
| 9bdbe943ce | |||
| 180220a2e3 | |||
| 8ef4af45d7 | |||
| 9215aa7ece | |||
| b497c5da71 | |||
| bf4d2fef4a | |||
| c053b8fc8a | |||
| d364ac6024 | |||
| d78be5112b | |||
| b5233eea56 | |||
| 09a6612742 | |||
| 1778ad620f | |||
| 458b50bc07 | |||
| fca8784dc3 | |||
| a846ee2321 | |||
| df087b592f | |||
| eade931650 | |||
| a7649f5b42 | |||
| f0b953dec9 | |||
| bb8196653f | |||
| a1b44ddd58 | |||
| 48b0d7f434 | |||
| d8b6b257f4 | |||
| c98972a3e0 | |||
| b93759936c | |||
| d62dda8140 | |||
| ca36fba7e4 | |||
| 743bf45e00 | |||
| 9bc5d21185 | |||
| c8b56bd161 | |||
| fe20079300 | |||
| 068d7c1b44 | |||
| 42fed60e61 | |||
| 53c1ccaa42 | |||
| 72f667cac9 | |||
| 4fff472808 | |||
| cfd74c2954 | |||
| 9bcca974ba | |||
| a40586d092 | |||
| bc9708f51a | |||
| 8ef36ed939 | |||
| c7f62bae9b | |||
| 1b741bf2b7 | |||
| 266d70816f | |||
| 27cedf09e8 | |||
| db9f1182f5 | |||
| f7fd5cf2d8 | |||
| 8d9c9a16e3 | |||
| 82deccac40 | |||
| 0e540dc3da | |||
| 897f2bc5fd | |||
| 750b0e5c18 | |||
| a65ac105cc | |||
| 6970c80d34 | |||
| dfbc42f833 | |||
| e356daa229 | |||
| 1c27ecb66f | |||
| d01d0bb358 | |||
| 8fcf3658b1 | |||
| b37535bcfb | |||
| ee0a10ec51 | |||
| 39e0333663 | |||
| 3afd2c3597 | |||
| bd19f3baa3 | |||
| 908fa84d49 | |||
| 571f34e0e6 | |||
| 01723025d7 | |||
| 505b5ee565 | |||
| 26ac03a3f6 | |||
| c9aa88b8ef | |||
| 887ac286ff | |||
| b1083d78c7 | |||
| 7863bdb484 | |||
| 5c3363bf25 | |||
| 9404bb8712 | |||
| 20e22d4507 | |||
| 9118e91b72 | |||
| fbbaa5e580 | |||
| 97a2cb4a37 | |||
| 6dee98c3a1 | |||
| 484ccf830a | |||
| 5690204224 | |||
| b203314c2f | |||
| 5ae8fd1f6f | |||
| c80da7eb0d | |||
| 326ca4202e | |||
| 852dde671e | |||
| bf613175e7 | |||
| 4d62cca267 | |||
| a63aa143bb | |||
| ed0fb774b9 | |||
| 9be956f4bc | |||
| 48d741f68a | |||
| 35e6b8a67d | |||
| 8a31ae14a0 | |||
| 26ee3fb93e | |||
| 8872d5ebfc | |||
| faf455283d | |||
| 562b4c5020 | |||
| 7460734522 | |||
| 3be7100e89 |
@@ -1,119 +0,0 @@
|
||||
version: 2.1
|
||||
|
||||
commands:
|
||||
submodules:
|
||||
steps:
|
||||
- run:
|
||||
name: "Pull submodules"
|
||||
command: git submodule update --init
|
||||
llvm-source-linux:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-19-v1
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-19-v1
|
||||
paths:
|
||||
- llvm-project/clang/lib/Headers
|
||||
- llvm-project/clang/include
|
||||
- llvm-project/compiler-rt
|
||||
- llvm-project/lld/include
|
||||
- llvm-project/llvm/include
|
||||
hack-ninja-jobs:
|
||||
steps:
|
||||
- run:
|
||||
name: "Hack Ninja to use less jobs"
|
||||
command: |
|
||||
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
|
||||
chmod +x /go/bin/ninja
|
||||
build-binaryen-linux:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- binaryen-linux-v3
|
||||
- run:
|
||||
name: "Build Binaryen"
|
||||
command: |
|
||||
make binaryen
|
||||
- save_cache:
|
||||
key: binaryen-linux-v3
|
||||
paths:
|
||||
- build/wasm-opt
|
||||
test-linux:
|
||||
parameters:
|
||||
llvm:
|
||||
type: string
|
||||
fmt-check:
|
||||
type: boolean
|
||||
default: true
|
||||
steps:
|
||||
- checkout
|
||||
- submodules
|
||||
- run:
|
||||
name: "Install apt dependencies"
|
||||
command: |
|
||||
echo 'deb https://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
apt-get update
|
||||
apt-get install --no-install-recommends -y \
|
||||
llvm-<<parameters.llvm>>-dev \
|
||||
clang-<<parameters.llvm>> \
|
||||
libclang-<<parameters.llvm>>-dev \
|
||||
lld-<<parameters.llvm>> \
|
||||
cmake \
|
||||
ninja-build
|
||||
- hack-ninja-jobs
|
||||
- build-binaryen-linux
|
||||
- restore_cache:
|
||||
keys:
|
||||
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||
- go-cache-v4-{{ checksum "go.mod" }}
|
||||
- llvm-source-linux
|
||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||
- when:
|
||||
condition: <<parameters.fmt-check>>
|
||||
steps:
|
||||
- run:
|
||||
# Do this before gen-device so that it doesn't check the
|
||||
# formatting of generated files.
|
||||
name: Check Go code formatting
|
||||
command: make fmt-check lint
|
||||
- run: make gen-device -j4
|
||||
# TODO: change this to -skip='TestErrors|TestWasm' with Go 1.20
|
||||
- run: go test -tags=llvm<<parameters.llvm>> -short -run='TestBuild|TestTest|TestGetList|TestTraceback'
|
||||
- run: make smoketest XTENSA=0
|
||||
- save_cache:
|
||||
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
- /go/pkg/mod
|
||||
|
||||
jobs:
|
||||
test-oldest:
|
||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||
# least the smoke tests still pass.
|
||||
docker:
|
||||
- image: golang:1.22-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "15"
|
||||
resource_class: large
|
||||
test-newest:
|
||||
# This tests the latest supported LLVM version when linking against system
|
||||
# libraries.
|
||||
docker:
|
||||
- image: golang:1.25-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "20"
|
||||
resource_class: large
|
||||
|
||||
workflows:
|
||||
test-all:
|
||||
jobs:
|
||||
- test-oldest
|
||||
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
|
||||
# - test-newest
|
||||
@@ -1,5 +1,4 @@
|
||||
build/
|
||||
llvm-*/
|
||||
.github
|
||||
.circleci
|
||||
|
||||
|
||||
@@ -16,21 +16,22 @@ jobs:
|
||||
name: build-macos
|
||||
strategy:
|
||||
matrix:
|
||||
# macos-13: amd64 (oldest supported version as of 18-10-2024)
|
||||
# macos-14: arm64 (oldest arm64 version)
|
||||
os: [macos-13, macos-14]
|
||||
# macos-14: arm64 (oldest supported version as of 18-11-2025)
|
||||
# macos-15-intel: amd64 (last intel version to be supported by github runners)
|
||||
# See https://github.com/actions/runner-images/issues/13046
|
||||
os: [macos-14, macos-15-intel]
|
||||
include:
|
||||
- os: macos-13
|
||||
goarch: amd64
|
||||
- os: macos-14
|
||||
goarch: arm64
|
||||
- os: macos-15-intel
|
||||
goarch: amd64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -39,10 +40,10 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.1'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-${{ matrix.os }}-v1
|
||||
@@ -56,7 +57,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -67,7 +68,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-${{ matrix.os }}-v2
|
||||
@@ -84,7 +85,7 @@ jobs:
|
||||
make llvm-build
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
@@ -100,16 +101,11 @@ jobs:
|
||||
- name: Make release artifact
|
||||
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
# https://github.com/actions/upload-artifact/issues/39
|
||||
# We can essentially pick one of these:
|
||||
# - have a double-zipped artifact when downloaded from the UI
|
||||
# - have a very slow artifact upload
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
|
||||
archive: false
|
||||
- name: Smoke tests
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||
test-macos-homebrew:
|
||||
@@ -120,7 +116,7 @@ jobs:
|
||||
version: [16, 17, 18, 19, 20]
|
||||
steps:
|
||||
- name: Set up Homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
uses: Homebrew/actions/setup-homebrew@main
|
||||
- name: Fix Python symlinks
|
||||
run: |
|
||||
# Github runners have broken symlinks, so relink
|
||||
@@ -129,12 +125,13 @@ jobs:
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
brew install llvm@${{ matrix.version }}
|
||||
brew link llvm@${{ matrix.version }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.1'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# This CI job checks whether at least the smoke tests pass for the oldest
|
||||
# Go/LLVM version we claim to support.
|
||||
|
||||
name: Version compatibility test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- release
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test-compat:
|
||||
runs-on: ubuntu-22.04 # this must be a specific version for the apt install below
|
||||
env:
|
||||
# Oldest versions currently supported by TinyGo
|
||||
LLVM: "15"
|
||||
Go: "1.24" # when updating this, also update minorMin in builder/config.go
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.Go }}
|
||||
cache: true
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ env.LLVM }} 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-${{ env.LLVM }}-dev \
|
||||
clang-${{ env.LLVM }} \
|
||||
libclang-${{ env.LLVM }}-dev \
|
||||
lld-${{ env.LLVM }} \
|
||||
binaryen
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-compat
|
||||
path: llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
path: llvm-project/compiler-rt
|
||||
- name: Go cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-build-${{ env.Go }}-llvm${{ env.LLVM }}-${{ hashFiles('go.sum') }}
|
||||
- name: Build TinyGo
|
||||
run: go install -tags=llvm${{ env.LLVM }}
|
||||
- run: tinygo version
|
||||
- run: make gen-device -j4
|
||||
- run: go test -tags=llvm${{ env.LLVM }} -short -skip=TestErrors
|
||||
- run: make smoketest XTENSA=0
|
||||
@@ -31,14 +31,14 @@ jobs:
|
||||
sudo rm -rf /usr/local/share/boost
|
||||
df -h
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
tinygo/tinygo-dev
|
||||
@@ -47,18 +47,18 @@ jobs:
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -66,45 +66,3 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Trigger Drivers repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger Bluetooth repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyFS repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyFont repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyDraw repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyTerm repo build on Github Actions
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
|
||||
+82
-52
@@ -12,18 +12,36 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
go-mod-tidy:
|
||||
# Check that go.sum is up to date.
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Run go mod tidy
|
||||
run: go mod tidy
|
||||
- name: Check go.mod and go.sum are up to date
|
||||
run: git diff --exit-code
|
||||
|
||||
build-linux:
|
||||
# Build Linux binaries, ready for release.
|
||||
# This runs inside an Alpine Linux container so we can more easily create a
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.25-alpine
|
||||
image: golang:1.26-alpine
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v4
|
||||
# tar: needed for actions/cache@v5
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh make g++ ruby-dev mold
|
||||
@@ -31,24 +49,24 @@ jobs:
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-linux-alpine-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-alpine-v1
|
||||
key: llvm-source-20-linux-alpine-v2
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -59,7 +77,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -70,10 +88,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-alpine-v1
|
||||
key: llvm-build-20-linux-alpine-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -88,16 +106,16 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-alpine-v1
|
||||
key: binaryen-linux-alpine-v2
|
||||
path: build/wasm-opt
|
||||
- name: Build Binaryen
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
@@ -118,26 +136,31 @@ jobs:
|
||||
make release deb -j3 STATIC=1
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: "Publish release artifact: tarball"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
/tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
/tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
name: tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
path: /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
archive: false
|
||||
- name: "Publish release artifact: Debian package"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
path: /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
archive: false
|
||||
test-linux-build:
|
||||
# Test the binaries built in the build-linux job by running the smoke tests.
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
@@ -146,9 +169,9 @@ jobs:
|
||||
- name: Install wasm-tools
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Download release artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
|
||||
- name: Extract release tarball
|
||||
run: |
|
||||
mkdir -p ~/lib
|
||||
@@ -164,7 +187,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
@@ -179,14 +202,14 @@ jobs:
|
||||
simavr \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: '22'
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
@@ -194,7 +217,7 @@ jobs:
|
||||
- name: Setup `wasm-tools`
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-asserts-v1
|
||||
@@ -208,7 +231,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -219,7 +242,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-asserts-v1
|
||||
@@ -235,13 +258,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-asserts-v1
|
||||
@@ -261,6 +284,8 @@ jobs:
|
||||
- run: make smoketest
|
||||
- run: make wasmtest
|
||||
- run: make tinygo-test-baremetal
|
||||
- name: Check Go code formatting
|
||||
run: make fmt-check lint
|
||||
build-linux-cross:
|
||||
# Build ARM Linux binaries, ready for release.
|
||||
# This intentionally uses an older Linux image, so that we compile against
|
||||
@@ -284,7 +309,7 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Get TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
@@ -296,12 +321,12 @@ jobs:
|
||||
g++-${{ matrix.toolchain }} \
|
||||
libc6-dev-${{ matrix.libc }}-cross
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-v1
|
||||
@@ -315,7 +340,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -326,7 +351,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-${{ matrix.goarch }}-v1
|
||||
@@ -344,13 +369,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-${{ matrix.goarch }}-v4
|
||||
@@ -370,9 +395,9 @@ jobs:
|
||||
run: |
|
||||
make CROSS=${{ matrix.toolchain }}
|
||||
- name: Download amd64 release
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
|
||||
- name: Extract amd64 release
|
||||
run: |
|
||||
mkdir -p build/release
|
||||
@@ -384,12 +409,17 @@ jobs:
|
||||
- name: Create ${{ matrix.goarch }} release
|
||||
run: |
|
||||
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
|
||||
- name: "Publish release artifact: tarball"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
/tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
/tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
path: /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
archive: false
|
||||
- name: "Publish release artifact: Debian package"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
path: /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
|
||||
archive: false
|
||||
|
||||
@@ -25,14 +25,14 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
tinygo/llvm-20
|
||||
@@ -46,13 +46,13 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
target: tinygo-llvm-build
|
||||
context: .
|
||||
|
||||
@@ -21,12 +21,12 @@ jobs:
|
||||
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
|
||||
run: sudo apt-get remove llvm-18
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Pull musl, bdwgc
|
||||
run: |
|
||||
git submodule update --init lib/musl lib/bdwgc
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-nix-v1
|
||||
@@ -36,13 +36,13 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: cachix/install-nix-action@v31
|
||||
- name: Test
|
||||
run: |
|
||||
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
|
||||
|
||||
@@ -20,14 +20,14 @@ jobs:
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-sizediff-v1
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
|
||||
@@ -17,21 +17,14 @@ jobs:
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install ninja binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -39,15 +32,15 @@ jobs:
|
||||
shell: bash
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-windows-v1
|
||||
key: llvm-source-20-windows-v3
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -58,7 +51,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save cached LLVM source
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -69,10 +62,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore cached LLVM build
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-windows-v2
|
||||
key: llvm-build-20-windows-v5
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -86,20 +79,21 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save cached LLVM build
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Go cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-windows-v3-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
C:/Users/runneradmin/AppData/Local/go-build
|
||||
C:/Users/runneradmin/go/pkg/mod
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install wasmtime@29.0.1
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
@@ -114,50 +108,35 @@ jobs:
|
||||
working-directory: build/release
|
||||
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
# https://github.com/actions/upload-artifact/issues/39
|
||||
# We can essentially pick one of these:
|
||||
# - have a dobule-zipped artifact when downloaded from the UI
|
||||
# - have a very slow artifact upload
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ steps.version.outputs.version }}
|
||||
name: tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
|
||||
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
|
||||
archive: false
|
||||
|
||||
smoke-test-windows:
|
||||
runs-on: windows-2022
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
@@ -166,28 +145,19 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
|
||||
@@ -195,34 +165,24 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop install binaryen && scoop install wasmtime@29.0.1
|
||||
scoop config use_external_7zip true
|
||||
scoop install binaryen wasmtime@29.0.1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.0'
|
||||
go-version: '1.26.4'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Test stdlib packages on wasip1
|
||||
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
url = https://github.com/WebAssembly/wasi-libc
|
||||
[submodule "lib/picolibc"]
|
||||
path = lib/picolibc
|
||||
url = https://github.com/keith-packard/picolibc.git
|
||||
url = https://github.com/picolibc/picolibc.git
|
||||
[submodule "lib/stm32-svd"]
|
||||
path = lib/stm32-svd
|
||||
url = https://github.com/tinygo-org/stm32-svd
|
||||
|
||||
+258
@@ -1,3 +1,261 @@
|
||||
0.41.1
|
||||
---
|
||||
* **machine**
|
||||
- esp32c3: correct pin interrupt setup call that was overlooked from #5320
|
||||
* **runtime**
|
||||
- esp32s3: wait for TIMG0 update register to clear before reading timer registers
|
||||
* **net**
|
||||
- update net module to a version that is backwards compatible with Go 1.25.x to fix #5332
|
||||
|
||||
0.41.0
|
||||
---
|
||||
* **general**
|
||||
- go.mod, compiler: bump minimum Go version to 1.23
|
||||
- builder: support Go 1.26 now
|
||||
- feat: add inheritable-only field to filter processor-level targets (#5270)
|
||||
- feature: add esp32flash flash method for esp32s3/esp32c3/esp32/esp8266
|
||||
- flashing: introduce flash method 'esp32jtag' for esp32c3/esp32s3 targets
|
||||
- fashing: add "adb" flash method using Android Debug Bridge
|
||||
- main: auto-use best available flashing options on esp32
|
||||
- espflasher: update to espflasher 0.6.0
|
||||
* **compiler**
|
||||
- implement method-set based AssignableTo and Implements (#5304)
|
||||
- simplify createObjectLayout
|
||||
- implement copy directly
|
||||
- fix min/max on floats by using intrinsics
|
||||
- add element layout to sliceAppend
|
||||
- add intrinsic for crypto/internal/constanttime.boolToUint8
|
||||
- fix SyscallN handling for Windows on Go 1.26+
|
||||
* **core**
|
||||
- reflect: add TypeAssert
|
||||
- reflect: fix TypeAssert for structs
|
||||
- sync: add WaitGroup.Go
|
||||
- os: add UserCacheDir and UserConfigDir
|
||||
- os: implement Lchown function for changing file ownership (#5161)
|
||||
- testing: add b.ReportMetric()
|
||||
- errors: add errors package to passing list
|
||||
- internal/gclayout: use correct lengths
|
||||
- internal/abi: add EscapeNonString, EscapeToResultNonString
|
||||
- internal, runtime: add internal fips bool
|
||||
- internal/itoa: resurrect from Go stdlib
|
||||
- internal/syscall/unix: implement GetRandom for WASI targets
|
||||
- interp: make ptrtoint size mismatch a recoverable error
|
||||
- loader: support "all:" prefix in //go:embed patterns
|
||||
- loader, crypto/internal/entropy: fix 32 MiB RAM overflow on microcontrollers
|
||||
- loader, unicode/utf8: fix hiBits overflow on 16-bit AVR targets
|
||||
- builder: order embedded files deterministically
|
||||
- builder: fix panic in findPackagePath when using -size short
|
||||
- builder: fix SIGSEGV when stripping duplicate function definitions
|
||||
- builder, runtime: fix duplicate symbol error with Go 1.26+ on Windows
|
||||
- builder: use target-specific -march for RISC-V library compilation
|
||||
- transform: modify output format from the -print-allocs flag to match the go coverage tool format
|
||||
- cgo: allow for changes to 'short-enums' flag
|
||||
- wasm: add more stubbed file operations
|
||||
* **machine**
|
||||
- esp32c3: implement BlockDevice for esp32c3 flash
|
||||
- esp32c3: clear GPIO STATUS before dispatching pin callbacks
|
||||
- esp32c3: implement USBDevice using interrupts
|
||||
- esp32c3: add Enable stub for QEMU test target
|
||||
- esp32c3: fix interrupt disable handling
|
||||
- esp32c3: clear MCAUSE after handling interrupt
|
||||
- esp32c3: map missing IRAM sections in linker script
|
||||
- esp32c3: fix to use PROVIDE() for WiFi/BLE ROM function addresses to allow blob overrides
|
||||
- esp32c3: add WiFi/BLE ROM linker support
|
||||
- esp32c3: use TIMG0 alarm interrupt for sleepTicks instead of busy-waiting
|
||||
- esp32s3: implement Pin.SetInterrupt for GPIO pin change interrupts
|
||||
- esp32s3: use edge-triggered CPU interrupt for GPIO pin interrupts
|
||||
- esp32s3: add interrupt support (#5244)
|
||||
- esp32s3: switch USB implementation to use interrupts instead of polling
|
||||
- esp32s3: replace inline ISR with full interrupt vector handler
|
||||
- esp32s3: use TIMG0 alarm interrupt for sleepTicks
|
||||
- esp32s3: improve exception handlers, add procPin/procUnpin, and linker wrap flags
|
||||
- esp32s3: fix Xtensa register window spill using recursive call4 in task switching
|
||||
- esp32s3: update linker script and boot assembly for multi-page flash XIP mapping
|
||||
- esp32s3: add flash XIP boot assembly with cache/MMU init
|
||||
- esp32s3: implement SPI (#5169)
|
||||
- esp32s3: implement I2C interface (#5210)
|
||||
- esp32s3: implement RNG based on onboard hardware random number generator
|
||||
- esp32s3,esp32c3: add USB serial support
|
||||
- esp32s3,esp32c3: add txStalled flag to skip USB serial spin when no host
|
||||
- esp32s3,esp32c3: make USB Serial/JTAG writes non-blocking when FIFO is full
|
||||
- esp32c3/esp32s3: refactor ADC implementation to reduce code duplication
|
||||
- esp32s3,esp32c3: add ADC support (#5231)
|
||||
- esp32s3,esp32c3: add PWM support (#5215)
|
||||
- esp32c3/esp32s3: refactoring and corrections for SPI implementation
|
||||
- esp32xx: add WASM simulator support for ESP32-C3/ESP32-S3 targets
|
||||
- esp32: default SPI CS pin to NoPin when unset
|
||||
- esp: fix tinygo_scanCurrentStack to spill register windows
|
||||
- stm32: fix UART interrupt storm caused by uncleared overrun error
|
||||
- stm32: fix PWM problem due to register shifting
|
||||
- stm32: add STM32U585 target definition and runtime
|
||||
- stm32: add STM32U5 GPIO, pin interrupts, and UART support
|
||||
- stm32: add STM32U5 I2C support
|
||||
- stm32: add STM32U5 SPI support
|
||||
- stm32u585: implement ADC
|
||||
- stm32g0b1: add support (#5150)
|
||||
- stm32g0b1: add Watchdog + ADC support (#5158)
|
||||
- stm32l0: add flash support
|
||||
- stm32l0x1,l0x2: TIM: adapt to 32-bit register access
|
||||
- stm32g0: sync with updated stm32 device files
|
||||
- attiny85: add USI-based SPI support (#5181)
|
||||
- attiny85: add PWM support (#5171)
|
||||
- rp: add Close function to UART to allow for removing all system resources/power usage
|
||||
- rp: use blockReset() and unresetBlockWait() helper functions for peripheral reset/unreset
|
||||
- rp2: prevent PWM Period method overflow
|
||||
- rp2: add per-byte timeout budget for I2C (#5189)
|
||||
- feather-m0: export UART0 and pins
|
||||
- usb/cdc: better ring buffer implementation (#5209)
|
||||
- fix: replace ! with ~ for register mask
|
||||
- atmega328p_simulator: add correct build tag for arduino_uno after renaming
|
||||
* **net**
|
||||
- update to Go 1.26.2 net package with UDP and JS improvements
|
||||
* **runtime**
|
||||
- implement fminimum/fmaximum
|
||||
- make timeoffset atomic
|
||||
- add MemStats.HeapObjects
|
||||
- handle GODEBUG on wasip2 (#5312)
|
||||
- fix Darwin syscall return value truncation and lost arguments
|
||||
- add syscall.runtimeClearenv for Go 1.26
|
||||
- split syscall functions for darwin changes for 1.26
|
||||
- fix: init heap before random number seed on wasm platforms
|
||||
* **targets**
|
||||
- add esp32s3-supermini board target
|
||||
- add support for Seeedstudio Xiao-RP2350 board
|
||||
- add Shrike Lite board (#5170)
|
||||
- rename arduino target to arduino-uno
|
||||
- add pins/setup for Arduino UNO Q board QWIIC connector
|
||||
- correct pin mapping for Arduino UNO Q STM32 MCU
|
||||
- add stm32u585 openocd commands for flashing on Arduino UNO Q
|
||||
- correct name/tag use for esp32s3-wroom1 board
|
||||
- modify esp32, esp32s3, esp32c3, & esp8266 targets to use built-in esp32flash
|
||||
- switch rp2040/rp2350 to default to tasks scheduler
|
||||
- change default stack size for esp32c3 and esp32s3 to 8196
|
||||
- swan: rename group build tag stm32l4x5 => stm32l4y5 to avoid clash with stm32 device name
|
||||
- nucleo-f722ze: add build-tag stm32f722
|
||||
- fix: set stm32u5x clock rate to default
|
||||
- create generic targets for esp32 boards
|
||||
* **libs**
|
||||
- stm32-svd: update submodule
|
||||
- update tools/gen-device-svd for recent changes to stm32-svd file structure (#5212)
|
||||
* **build/test**
|
||||
- build: use Golang 1.26 for all builds
|
||||
- build: actually use the version of llvm we are supposed to be testing by using brew link command
|
||||
- build: let scoop run updates to resolve binaryen install failures on Windows
|
||||
- ci: don't double zip release artifacts
|
||||
- test: increase default timeout from 1 to 2 minutes to prevent spurious CI fails
|
||||
- testdata: fix flaky timers test by draining ticker channel after Stop
|
||||
- testdata: more corpus entries (#5182)
|
||||
- add soypat/lneto to corpus
|
||||
- GNUmakefile: add context and expvar to stdlib tests
|
||||
- GNUmakefile: add encoding/xml to stdlib tests on Linux
|
||||
- main (test): skip mipsle test if the emulator is missing
|
||||
- make: remove machine without board from smoketest
|
||||
- stm32: add Arduino UNO Q to smoketests
|
||||
- flake: bump to nixpkgs 25.11
|
||||
- chore: update all github actions to latest versions
|
||||
- fix: use external 7zip for scoop installs on Windows
|
||||
|
||||
0.40.1
|
||||
---
|
||||
* **machine**
|
||||
- nrf: fix flash writes when SoftDevice is enabled
|
||||
* **runtime**
|
||||
- runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
|
||||
- runtime: add calls to initRand() during run() for all schedulers
|
||||
- runtime: call initRand() before initHeap() during initialization
|
||||
- runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
|
||||
* **libs**
|
||||
- picolibc: use updated location for git repo
|
||||
|
||||
0.40.0
|
||||
---
|
||||
* **general**
|
||||
- all: add full LLVM 20 support
|
||||
- core: feat: enable //go:linkname pragma for globals
|
||||
- core: feature: Add flag to ignore go compatibility matrix (#5078)
|
||||
- chore: update version for 0.40 development cycle
|
||||
* **compiler**
|
||||
- emit an error when the actual arch doesn't match GOARCH
|
||||
- mark string parameters as readonly
|
||||
- use Tarjan's SCC algorithm to detect loops for defer
|
||||
- lower "large stack" limit to 16kb
|
||||
* **core**
|
||||
- shrink bdwgc library
|
||||
- Fix linker errors for runtime.vgetrandom and crypto/internal/sysrand.fatal
|
||||
- fix: add TryLock to sync.RWMutex
|
||||
- fix: correct linter issues exposed by the fix in #4679
|
||||
- fix: don't hardcode success return state
|
||||
- fix: expand RTT debugger compatibility
|
||||
- internal/task (threads): save stack bounds instead of scanning under a lock
|
||||
- internal/task: create detached threads and fix error handling
|
||||
- interp: better errors when debugging interp
|
||||
- transform (gc): create stack slots in callers of external functions
|
||||
- internal/task: prevent semaphore resource leak for threads scheduler
|
||||
* **machine**
|
||||
- cortexm: optimize code size for the HardFault_Handler
|
||||
- fe310: add I2C pins for the HiFive1b
|
||||
- clarify WriteAt semantics of BlockDevice
|
||||
- fix deprecated AsmFull comment (#5005)
|
||||
- make sure DMA buffers do not escape unnecessarily
|
||||
- only enable USB-CDC when needed
|
||||
- use larger SPI MAXCNT on nrf52833 and nrf52840
|
||||
- fix: update m.queuedBytes when clamping output to avoid corrupting sentBytes
|
||||
- fix: use int64 in ReadTemperature to avoid overflow
|
||||
- fix(rp2): disable DBGPAUSE on startup
|
||||
- fix(rp2): possible integer overflow while computing factors for SPI baudrate
|
||||
- fix(rp2): reset spinlocks at startup
|
||||
- fix(rp2): switch spinlock busy loop to wfe
|
||||
- fix(rp2): use side-effect-free spinlocks
|
||||
- nrf: add ADC_VDDH which is an ADC pin for VDDH
|
||||
- nrf: don't block SPI transfer
|
||||
- nrf: don't set PSELN, it's ignored in single ended mode anyway
|
||||
- nrf: fix typo in ADC configuration
|
||||
- nrf: refactor SoftDevice enabled check
|
||||
- nrf: rename pwmPin to adcPin
|
||||
- nrf: support flash operations while the SoftDevice is enabled
|
||||
- rp2040: allow writing to the UART inside interrupts
|
||||
- machine,nrf528: stop the bus only once on I2C bus error and ensures the first error is returned
|
||||
* **net**
|
||||
- update submodule to latest commits
|
||||
* **runtime**
|
||||
- (avr): fix infinite longjmp loop if stack is aligned to 256 bytes
|
||||
- (gc_blocks.go): clear full size of allocation
|
||||
- (gc_blocks.go): make sweep branchless
|
||||
- (gc_blocks.go): simplify scanning logic
|
||||
- (gc_blocks.go): use a linked stack to scan marked objects
|
||||
- (gc_blocks.go): use best-fit allocation
|
||||
- (gc_boehm.go): fix world already stopped check
|
||||
- (wasm): scan the system stack
|
||||
- fix sleep duration for long sleeps
|
||||
- remove copied code for nrf52840
|
||||
- src/syscall: update src buffer after write
|
||||
- wasm: fix C realloc and optimize it a bit
|
||||
* **targets**
|
||||
- add xiao-esp32s3 board target
|
||||
- Add ESP32-S3 support (#5091)
|
||||
- Added Gopher ARCADE board
|
||||
- Create "pico2-ice" target board (#5062)
|
||||
* **build/test**
|
||||
- Add testing.T.Context() and testing.B.Context()
|
||||
- create separate go.mod file for testing dependencies for wasm tests that use Chromium headless browser to avoid use of older incompatible version.
|
||||
- go back to normal scheduler instead of tasks scheduler for macos CI
|
||||
- update CI to use Go 1.25.5
|
||||
- update macOS GH actions builds to handle sunset of macOS 13
|
||||
- use task scheduler on macOS builds to avoid test race condition lockups
|
||||
- update all CI builds to use latest stable Go release. Also update some of the actions to their latest releases.
|
||||
- update GH actions builds to use Go 1.25.4
|
||||
- uninstall cmake before install
|
||||
- fix: point the submodule for musl-lib to a mirror in the TinyGo GitHub org
|
||||
- fix: remove macOS 15 from CI build matrix (conflicts with macOS 14 build)
|
||||
- fix: separate host expected bytes from device intended bytes
|
||||
- fix/typo: makeESPFirmwareImage
|
||||
- make: GNUmakefile: shrink TinyGo binaries on Linux
|
||||
- move the directory list into a variable
|
||||
- several improvements to the macOS GH actions build
|
||||
- Fix for #4678: top-level 'make lint' wasn't working
|
||||
- fix: increase the timeout for chromedp to connect to the headless browser used for running the wasm tests.
|
||||
- testdata: some more packages for the test corpus
|
||||
|
||||
0.39.0
|
||||
---
|
||||
* **general**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.25 AS tinygo-llvm
|
||||
FROM golang:1.26 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-17 ninja-build && \
|
||||
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
|
||||
|
||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||
# all the build tools etc).
|
||||
FROM golang:1.25 AS tinygo-compiler
|
||||
FROM golang:1.26 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
+122
-21
@@ -142,6 +142,9 @@ ifeq ($(OS),Windows_NT)
|
||||
|
||||
# PIC needs to be disabled for libclang to work.
|
||||
LLVM_OPTION += -DLLVM_ENABLE_PIC=OFF
|
||||
# Statically link the C++ and GCC runtime into LLVM tools so they don't
|
||||
# depend on MinGW DLLs that may not be on PATH when executed during the build.
|
||||
LLVM_OPTION += '-DCMAKE_EXE_LINKER_FLAGS=-static-libgcc -static-libstdc++'
|
||||
|
||||
CGO_CPPFLAGS += -DCINDEX_NO_EXPORTS
|
||||
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
@@ -194,6 +197,12 @@ NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm lld $(addprefix lib/lib,
|
||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
||||
CGO_CXXFLAGS=-std=c++17
|
||||
ifneq ($(uname),Windows_NT)
|
||||
# Disable GCC DWARF compression: lld built without zlib cannot link
|
||||
# object files with ELFCOMPRESS_ZLIB debug sections.
|
||||
CGO_CFLAGS+=-gz=none
|
||||
CGO_CXXFLAGS+=-gz=none
|
||||
endif
|
||||
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||
endif
|
||||
|
||||
@@ -289,16 +298,16 @@ WASM_TOOLS_MODULE=go.bytecodealliance.org
|
||||
.PHONY: wasi-syscall
|
||||
wasi-syscall: wasi-cm
|
||||
rm -rf ./src/internal/wasi/*
|
||||
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
|
||||
go run $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
|
||||
|
||||
# Copy package cm into src/internal/cm
|
||||
.PHONY: wasi-cm
|
||||
wasi-cm:
|
||||
rm -rf ./src/internal/cm/*
|
||||
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
||||
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
||||
|
||||
# Check for Node.js used during WASM tests.
|
||||
MIN_NODEJS_VERSION=18
|
||||
MIN_NODEJS_VERSION=22
|
||||
|
||||
.PHONY: check-nodejs-version
|
||||
check-nodejs-version:
|
||||
@@ -310,7 +319,7 @@ check-nodejs-version:
|
||||
|
||||
tinygo: ## Build the TinyGo compiler
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " $(MAKE) llvm-source"; echo " $(MAKE) $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" .
|
||||
test: check-nodejs-version
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
|
||||
|
||||
@@ -339,14 +348,17 @@ TEST_PACKAGES_FAST = \
|
||||
embed/internal/embedtest \
|
||||
encoding \
|
||||
encoding/ascii85 \
|
||||
errors \
|
||||
encoding/asn1 \
|
||||
encoding/base32 \
|
||||
encoding/base64 \
|
||||
encoding/csv \
|
||||
encoding/hex \
|
||||
expvar \
|
||||
go/ast \
|
||||
go/format \
|
||||
go/scanner \
|
||||
go/token \
|
||||
go/version \
|
||||
hash \
|
||||
hash/adler32 \
|
||||
@@ -359,6 +371,7 @@ TEST_PACKAGES_FAST = \
|
||||
math/cmplx \
|
||||
net/http/internal/ascii \
|
||||
net/mail \
|
||||
net/url \
|
||||
os \
|
||||
path \
|
||||
reflect \
|
||||
@@ -375,32 +388,36 @@ TEST_PACKAGES_FAST = \
|
||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
||||
# bytes requires mmap
|
||||
# compress/flate appears to hang on wasi
|
||||
# crypto/aes fails on wasi, needs panic()/recover()
|
||||
# crypto/aes needs reflect.Type.Method(), not yet implemented
|
||||
# crypto/des fails on wasi, needs panic()/recover()
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# image requires recover(), which is not yet supported on wasi
|
||||
# encoding/xml takes a minute on linux and gives a stack overflow on wasi
|
||||
# image fails on wasi, needs panic()/recover()
|
||||
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# mime: fail on wasi; neds panic()/recover()
|
||||
# mime: fails on wasi, needs panic()/recover()
|
||||
# mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK
|
||||
# mime/quotedprintable requires syscall.Faccessat
|
||||
# net/mail: needs wasip1 syscall.FDFLAG_NONBLOCK
|
||||
# net/ntextproto: needs wasip1 syscall.FDFLAG_NONBLOCK
|
||||
# regexp/syntax: fails on wasip1; needs panic()/recover()
|
||||
# strconv requires recover() which is not yet supported on wasi
|
||||
# text/tabwriter requires recover(), which is not yet supported on wasi
|
||||
# text/template/parse requires recover(), which is not yet supported on wasi
|
||||
# regexp/syntax: fails on wasip1, needs panic()/recover()
|
||||
# strconv: fails on wasi, needs panic()/recover()
|
||||
# text/tabwriter: fails on wasi, needs panic()/recover()
|
||||
# text/template/parse: fails on wasi, needs panic()/recover()
|
||||
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
|
||||
# Additional standard library packages that pass tests on individual platforms
|
||||
TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
compress/flate \
|
||||
context \
|
||||
crypto/aes \
|
||||
crypto/des \
|
||||
crypto/ecdh \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
encoding/xml \
|
||||
image \
|
||||
io/ioutil \
|
||||
mime \
|
||||
@@ -412,6 +429,7 @@ TEST_PACKAGES_LINUX := \
|
||||
os/user \
|
||||
regexp/syntax \
|
||||
strconv \
|
||||
testing/fstest \
|
||||
text/tabwriter \
|
||||
text/template/parse
|
||||
|
||||
@@ -422,7 +440,11 @@ TEST_PACKAGES_WINDOWS := \
|
||||
compress/flate \
|
||||
crypto/des \
|
||||
crypto/hmac \
|
||||
image \
|
||||
mime \
|
||||
regexp/syntax \
|
||||
strconv \
|
||||
text/tabwriter \
|
||||
text/template/parse \
|
||||
$(nil)
|
||||
|
||||
@@ -437,6 +459,7 @@ TEST_PACKAGES_NONWASM = \
|
||||
crypto/ecdsa \
|
||||
debug/macho \
|
||||
embed/internal/embedtest \
|
||||
expvar \
|
||||
go/format \
|
||||
os \
|
||||
testing \
|
||||
@@ -470,25 +493,31 @@ report-stdlib-tests-pass:
|
||||
ifeq ($(uname),Darwin)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
|
||||
TEST_IOFS := true
|
||||
TEST_ENCODING_XML := true
|
||||
endif
|
||||
ifeq ($(uname),Linux)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
|
||||
TEST_IOFS := true
|
||||
TEST_ENCODING_XML := true
|
||||
endif
|
||||
ifeq ($(OS),Windows_NT)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
||||
TEST_IOFS := false
|
||||
endif
|
||||
|
||||
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
|
||||
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic|TestAsValidation'
|
||||
TEST_ADDITIONAL_FLAGS ?=
|
||||
|
||||
# Test known-working standard library packages.
|
||||
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
||||
.PHONY: tinygo-test
|
||||
tinygo-test:
|
||||
@# TestExtraMethods: used by many crypto packages and uses reflect.Type.Method which is not implemented.
|
||||
@# TestParseAndBytesRoundTrip/P256/Generic: relies on t.Skip() which is not implemented
|
||||
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
||||
@# TestParseAndBytesRoundTrip/P256/Generic: needs Goexit to run defers on wasm.
|
||||
$(TINYGO) test $(TEST_ADDITIONAL_FLAGS) $(TEST_SKIP_FLAG) $(filter-out encoding/xml,$(TEST_PACKAGES_HOST)) $(TEST_PACKAGES_SLOW)
|
||||
ifeq ($(TEST_ENCODING_XML),true)
|
||||
$(TINYGO) test $(TEST_ADDITIONAL_FLAGS) $(TEST_SKIP_FLAG) -stack-size=16MB encoding/xml
|
||||
endif
|
||||
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
|
||||
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
||||
@# For more details, see the comments on issue #3143.
|
||||
@@ -621,9 +650,11 @@ smoketest: testchdir
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
@@ -641,6 +672,8 @@ ifneq ($(WASM), 0)
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=xiao_esp32s3 examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
||||
@@ -729,6 +762,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao-ble-plus examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=rak4631 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
|
||||
@@ -765,6 +800,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico -gc=leaking examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1
|
||||
@@ -811,6 +848,10 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=vicharak_shrike-lite examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao-rp2350 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -870,18 +911,26 @@ ifneq ($(STM32), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32u031 examples/empty
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinkm
|
||||
@$(MD5SUM) test.hex
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno -scheduler=tasks examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -893,13 +942,25 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/mcp3008
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
|
||||
@@ -912,7 +973,46 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
# xiao-esp32c6
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c6 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c6 examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
# xiao-esp32s3
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/pwm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
# esp32s3-supermini
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-box-3 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
# esp32c3-supermini
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/pwm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
|
||||
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
|
||||
@@ -925,6 +1025,7 @@ endif
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
|
||||
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@@ -1095,8 +1196,8 @@ endif
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half
|
||||
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
|
||||
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp src build/release/tinygo/src
|
||||
@cp -rp targets build/release/tinygo/targets
|
||||
|
||||
@@ -1118,7 +1219,7 @@ endif
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
cd internal/tools && go generate -tags tools ./
|
||||
go generate -tags tools ./
|
||||
|
||||
LINTDIRS=src/os/ src/reflect/
|
||||
.PHONY: lint
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
Copyright (c) 2018-2025 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2026 The TinyGo Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of the Go standard library.
|
||||
Copyright (c) 2009-2024 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors. All rights reserved.
|
||||
See https://github.com/golang/go/blob/master/LICENSE for license information.
|
||||
|
||||
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
|
||||
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# TinyGo - Go compiler for small places
|
||||
|
||||
[](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://github.com/tinygo-org/tinygo/actions/workflows/nix.yml) [](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
|
||||
[](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://github.com/tinygo-org/tinygo/actions/workflows/nix.yml)
|
||||
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
|
||||
|
||||
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You can help TinyGo with a financial contribution using OpenCollective. Please see https://opencollective.com/tinygo for more information. Thank you!
|
||||
|
||||
## Embedded
|
||||
|
||||
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
|
||||
@@ -31,10 +34,10 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
The above program can be compiled and run without modification on an Arduino Uno, an Adafruit ItsyBitsy M0, or any of the supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
|
||||
The above program can be compiled and run without modification on an [Arduino Uno](https://tinygo.org/docs/reference/microcontrollers/boards/arduino-uno), an [Adafruit Circuit Playground Express](https://tinygo.org/docs/reference/microcontrollers/featured/circuitplay-express), a [Seeed Studio XIAO-ESP32S3](https://tinygo.org/docs/reference/microcontrollers/featured/xiao-esp32s3) or any of the many supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
|
||||
|
||||
```shell
|
||||
tinygo flash -target arduino examples/blinky1
|
||||
tinygo flash -target arduino-uno examples/blinky1
|
||||
```
|
||||
|
||||
## WebAssembly
|
||||
@@ -63,7 +66,7 @@ tinygo build -buildmode=c-shared -o add.wasm -target=wasip1 add.go
|
||||
You can also use the same syntax as Go 1.24+:
|
||||
|
||||
```shell
|
||||
GOARCH=wasip1 GOOS=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||
GOOS=wasip1 GOARCH=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
@@ -74,7 +77,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
### Embedded
|
||||
|
||||
You can compile TinyGo programs for over 94 different microcontroller boards.
|
||||
You can compile TinyGo programs for over 150 different microcontroller boards.
|
||||
|
||||
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
|
||||
|
||||
@@ -139,7 +142,7 @@ Non-goals:
|
||||
|
||||
## Why this project exists
|
||||
|
||||
> We never expected Go to be an embedded language and so its got serious problems...
|
||||
> We never expected Go to be an embedded language, and so it’s got serious problems...
|
||||
|
||||
-- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799)
|
||||
|
||||
|
||||
+65
-17
@@ -14,11 +14,13 @@ import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"hash/crc32"
|
||||
"maps"
|
||||
"math/bits"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -136,9 +138,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if _, ok := globalValues[pkgPath]; !ok {
|
||||
globalValues[pkgPath] = map[string]string{}
|
||||
}
|
||||
for k, v := range vals {
|
||||
globalValues[pkgPath][k] = v
|
||||
}
|
||||
maps.Copy(globalValues[pkgPath], vals)
|
||||
}
|
||||
|
||||
// Check for a libc dependency.
|
||||
@@ -254,6 +254,18 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
|
||||
}
|
||||
|
||||
// Strip default initializers for -X globals from the type info before
|
||||
// building SSA. This prevents go/ssa from emitting init stores for them,
|
||||
// so that makeGlobalsModule can supply the correct values at final link
|
||||
// time without any runtime init overwriting them. The -X values themselves
|
||||
// are kept out of the per-package build cache; only the variable names
|
||||
// appear in the cache key.
|
||||
for _, pkg := range lprogram.Sorted() {
|
||||
for name := range globalValues[pkg.Pkg.Path()] {
|
||||
pkg.StripVarInitializer(name)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the *ssa.Program. This does not yet build the entire SSA of the
|
||||
// program so it's pretty fast and doesn't need to be parallelized.
|
||||
program := lprogram.LoadSSA()
|
||||
@@ -265,7 +277,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
|
||||
var embedFileObjects []*compileJob
|
||||
for _, pkg := range lprogram.Sorted() {
|
||||
pkg := pkg // necessary to avoid a race condition
|
||||
|
||||
var undefinedGlobals []string
|
||||
for name := range globalValues[pkg.Pkg.Path()] {
|
||||
@@ -281,9 +292,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
allFiles[file.Name] = append(allFiles[file.Name], file)
|
||||
}
|
||||
}
|
||||
for name, files := range allFiles {
|
||||
name := name
|
||||
files := files
|
||||
// Sort embedded files by name to maintain output determinism.
|
||||
embedNames := make([]string, 0, len(allFiles))
|
||||
for _, files := range allFiles {
|
||||
embedNames = append(embedNames, files[0].Name)
|
||||
}
|
||||
slices.Sort(embedNames)
|
||||
for _, name := range embedNames {
|
||||
job := &compileJob{
|
||||
description: "make object file for " + name,
|
||||
run: func(job *compileJob) error {
|
||||
@@ -298,7 +313,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
sum := sha256.Sum256(data)
|
||||
hexSum := hex.EncodeToString(sum[:16])
|
||||
|
||||
for _, file := range files {
|
||||
for _, file := range allFiles[name] {
|
||||
file.Size = uint64(len(data))
|
||||
file.Hash = hexSum
|
||||
if file.NeedsData {
|
||||
@@ -472,7 +487,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if pkgInit.IsNil() {
|
||||
panic("init not found for " + pkg.Pkg.Path())
|
||||
}
|
||||
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
|
||||
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -541,6 +556,23 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load bitcode file: %w", err)
|
||||
}
|
||||
// Resolve duplicate function definitions before linking.
|
||||
// This can happen when a newer Go version adds a function
|
||||
// body in a standard library package that was previously
|
||||
// just a declaration provided by //go:linkname from the
|
||||
// runtime. In that case, keep the existing (runtime)
|
||||
// definition by weakening the new one's linkage so the
|
||||
// LLVM linker discards it in favor of the existing one.
|
||||
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
||||
if fn.IsDeclaration() {
|
||||
continue
|
||||
}
|
||||
existing := mod.NamedFunction(fn.Name())
|
||||
if existing.IsNil() || existing.IsDeclaration() {
|
||||
continue
|
||||
}
|
||||
fn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
err = llvm.LinkModules(mod, pkgMod)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to link module: %w", err)
|
||||
@@ -741,7 +773,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
// TODO: do this as part of building the package to be able to link the
|
||||
// bitcode files together.
|
||||
for _, pkg := range lprogram.Sorted() {
|
||||
pkg := pkg
|
||||
for _, filename := range pkg.CFiles {
|
||||
abspath := filepath.Join(pkg.OriginalDir(), filename)
|
||||
job := &compileJob{
|
||||
@@ -808,22 +839,25 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
|
||||
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
|
||||
if config.GOOS() == "windows" {
|
||||
// Options for the MinGW wrapper for the lld COFF linker.
|
||||
switch config.LinkerFlavor() {
|
||||
case "coff":
|
||||
// Options for driving ld.lld in PE/COFF mode.
|
||||
ldflags = append(ldflags,
|
||||
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),
|
||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
|
||||
} else if config.GOOS() == "darwin" {
|
||||
case "darwin":
|
||||
// Options for the ld64-compatible lld linker.
|
||||
ldflags = append(ldflags,
|
||||
"--lto-O"+strconv.Itoa(speedLevel),
|
||||
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
|
||||
} else {
|
||||
case "gnu":
|
||||
// Options for the ELF linker.
|
||||
ldflags = append(ldflags,
|
||||
"--lto-O"+strconv.Itoa(speedLevel),
|
||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
|
||||
)
|
||||
default:
|
||||
return fmt.Errorf("unknown linker flavor: %s", config.LinkerFlavor())
|
||||
}
|
||||
if config.CodeModel() != "default" {
|
||||
ldflags = append(ldflags,
|
||||
@@ -880,7 +914,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
|
||||
// Run wasm-opt for wasm binaries
|
||||
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
||||
if arch, _, _ := strings.Cut(config.Triple(), "-"); arch == "wasm32" {
|
||||
optLevel, _, _ := config.OptLevel()
|
||||
opt := "-" + optLevel
|
||||
|
||||
@@ -1042,7 +1076,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
case "esp32", "esp32-img", "esp32c3", "esp8266":
|
||||
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp32c6", "esp8266":
|
||||
// Special format for the ESP family of chips (parsed by the ROM
|
||||
// bootloader).
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
@@ -1174,7 +1208,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
|
||||
// needed to convert a program to its final form. Some transformations are not
|
||||
// optional and must be run as the compiler expects them to run.
|
||||
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
||||
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
|
||||
err := interp.Run(mod, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1318,6 +1352,14 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
|
||||
}
|
||||
baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize()
|
||||
|
||||
// Account for the bytes that tinygo_swapTask pushes onto the goroutine stack
|
||||
// on every context switch. The static analysis correctly traces Go calls,
|
||||
// but it cannot see into the assembly-level register push.
|
||||
var contextSwitchOverhead uint64
|
||||
if swapFuncs, ok := functions["tinygo_swapTask"]; ok && len(swapFuncs) == 1 {
|
||||
contextSwitchOverhead = swapFuncs[0].FrameSize
|
||||
}
|
||||
|
||||
sizes := make(map[string]functionStackSize)
|
||||
|
||||
// Add the reset handler function, for convenience. The reset handler runs
|
||||
@@ -1366,6 +1408,12 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
|
||||
// overflow will occur even before the goroutine is started.
|
||||
stackSize = baseStackSize
|
||||
}
|
||||
if stackSizeType == stacksize.Bounded {
|
||||
// Add the overhead of context switching. This is needed because the
|
||||
// context switch (tinygo_swapTask) pushes callee-saved registers
|
||||
// onto the current stack, which is not seen by the static analysis.
|
||||
stackSize += contextSwitchOverhead
|
||||
}
|
||||
sizes[name] = functionStackSize{
|
||||
stackSize: stackSize,
|
||||
stackSizeType: stackSizeType,
|
||||
|
||||
@@ -28,6 +28,8 @@ func TestClangAttributes(t *testing.T) {
|
||||
"cortex-m4",
|
||||
"cortex-m7",
|
||||
"esp32c3",
|
||||
"esp32c6",
|
||||
"esp32s3",
|
||||
"fe310",
|
||||
"gameboy-advance",
|
||||
"k210",
|
||||
@@ -45,7 +47,6 @@ func TestClangAttributes(t *testing.T) {
|
||||
targetNames = append(targetNames, "esp32", "esp8266")
|
||||
}
|
||||
for _, targetName := range targetNames {
|
||||
targetName := targetName
|
||||
t.Run(targetName, func(t *testing.T) {
|
||||
testClangAttributes(t, &compileopts.Options{Target: targetName})
|
||||
})
|
||||
|
||||
+1
-1
@@ -281,7 +281,7 @@ func parseDepFile(s string) ([]string, error) {
|
||||
s = strings.ReplaceAll(s, "\\\n", " ")
|
||||
|
||||
// Only use the first line, which is expected to begin with "deps:".
|
||||
line := strings.SplitN(s, "\n", 2)[0]
|
||||
line, _, _ := strings.Cut(s, "\n")
|
||||
if !strings.HasPrefix(line, "deps:") {
|
||||
return nil, errors.New("readDepFile: expected 'deps:' prefix")
|
||||
}
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ struct AssemblerInvocation {
|
||||
EmitDwarfUnwindType EmitDwarfUnwind;
|
||||
|
||||
// Whether to emit compact-unwind for non-canonical entries.
|
||||
// Note: maybe overriden by other constraints.
|
||||
// Note: maybe overridden by other constraints.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned EmitCompactUnwindNonCanonical : 1;
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import (
|
||||
var commands = map[string][]string{}
|
||||
|
||||
func init() {
|
||||
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
||||
llvmMajor, _, _ := strings.Cut(llvm.Version, ".")
|
||||
commands["clang"] = []string{"clang-" + llvmMajor}
|
||||
commands["ld.lld"] = []string{"ld.lld-" + llvmMajor, "ld.lld"}
|
||||
commands["wasm-ld"] = []string{"wasm-ld-" + llvmMajor, "wasm-ld"}
|
||||
|
||||
+9
-6
@@ -25,18 +25,21 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
}
|
||||
|
||||
// Version range supported by TinyGo.
|
||||
const minorMin = 19
|
||||
const minorMax = 25
|
||||
const minorMin = 24 // when updating the min version, also update .github/workflows/compat.yml
|
||||
const minorMax = 26
|
||||
|
||||
// Check that we support this Go toolchain version.
|
||||
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||
|
||||
if options.GoCompatibility {
|
||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the Go toolchain version isn't too new, if we haven't been
|
||||
|
||||
@@ -15,7 +15,7 @@ func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJ
|
||||
return &compileJob{
|
||||
description: "compile Darwin libSystem.dylib",
|
||||
run: func(job *compileJob) (err error) {
|
||||
arch := strings.Split(config.Triple(), "-")[0]
|
||||
arch, _, _ := strings.Cut(config.Triple(), "-")
|
||||
job.result = filepath.Join(tmpdir, "libSystem.dylib")
|
||||
objpath := filepath.Join(tmpdir, "libSystem.o")
|
||||
inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s")
|
||||
|
||||
+16
-3
@@ -100,11 +100,24 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
|
||||
chip_id := map[string]uint16{
|
||||
"esp32": 0x0000,
|
||||
"esp32c3": 0x0005,
|
||||
"esp32c6": 0x000d,
|
||||
"esp32s3": 0x0009,
|
||||
}[chip]
|
||||
|
||||
// SPI flash speed/size byte (byte 3 of header):
|
||||
// Upper nibble = flash size, lower nibble = flash frequency.
|
||||
// The espflasher auto-detects and patches the flash size (upper nibble),
|
||||
// but the frequency (lower nibble) must be correct per chip.
|
||||
spiSpeedSize := map[string]uint8{
|
||||
"esp32": 0x1f, // 80MHz=0x0F, 2MB=0x10
|
||||
"esp32c3": 0x1f, // 80MHz=0x0F, 2MB=0x10
|
||||
"esp32c6": 0x10, // 80MHz=0x00, 2MB=0x10 (C6 uses different freq encoding)
|
||||
"esp32s3": 0x1f, // 80MHz=0x0F, 2MB=0x10
|
||||
}[chip]
|
||||
|
||||
// Image header.
|
||||
switch chip {
|
||||
case "esp32", "esp32c3":
|
||||
case "esp32", "esp32c3", "esp32s3", "esp32c6":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
||||
// Note: not adding a SHA256 hash as the binary is modified by
|
||||
@@ -125,8 +138,8 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
|
||||
spi_speed_size: 0x1f, // ESP_IMAGE_SPI_SPEED_80M, ESP_IMAGE_FLASH_SIZE_2MB
|
||||
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
|
||||
spi_speed_size: spiSpeedSize,
|
||||
entry_addr: uint32(inf.Entry),
|
||||
wp_pin: 0xEE, // disable WP pin
|
||||
chip_id: chip_id,
|
||||
|
||||
+2
-2
@@ -195,11 +195,11 @@ type intHeap struct {
|
||||
sort.IntSlice
|
||||
}
|
||||
|
||||
func (h *intHeap) Push(x interface{}) {
|
||||
func (h *intHeap) Push(x any) {
|
||||
h.IntSlice = append(h.IntSlice, x.(int))
|
||||
}
|
||||
|
||||
func (h *intHeap) Pop() interface{} {
|
||||
func (h *intHeap) Pop() any {
|
||||
x := h.IntSlice[len(h.IntSlice)-1]
|
||||
h.IntSlice = h.IntSlice[:len(h.IntSlice)-1]
|
||||
return x
|
||||
|
||||
+17
-4
@@ -167,9 +167,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
// double.
|
||||
args = append(args, "-mdouble=64")
|
||||
case "riscv32":
|
||||
args = append(args, "-march=rv32imac", "-fforce-enable-int128")
|
||||
args = append(args, "-march="+riscvMarch(config, "rv32imac"), "-fforce-enable-int128")
|
||||
case "riscv64":
|
||||
args = append(args, "-march=rv64gc")
|
||||
args = append(args, "-march="+riscvMarch(config, "rv64gc"))
|
||||
case "mips":
|
||||
args = append(args, "-fno-pic")
|
||||
}
|
||||
@@ -218,7 +218,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
return err
|
||||
}
|
||||
// Store this archive in the cache.
|
||||
return os.Rename(f.Name(), archiveFilePath)
|
||||
return robustRename(f.Name(), archiveFilePath)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -232,7 +232,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
}
|
||||
for _, path := range paths {
|
||||
// Strip leading "../" parts off the path.
|
||||
path := path
|
||||
cleanpath := path
|
||||
for strings.HasPrefix(cleanpath, "../") {
|
||||
cleanpath = cleanpath[3:]
|
||||
@@ -298,3 +297,17 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
once.Do(unlock)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// riscvMarch returns the -march value for RISC-V library compilation.
|
||||
// It extracts the value from the target's cflags if present, otherwise
|
||||
// falls back to the provided default. This ensures libraries are compiled
|
||||
// with the correct ISA extensions for each target (e.g. rv32imc for
|
||||
// ESP32-C3 which lacks the atomic extension).
|
||||
func riscvMarch(config *compileopts.Config, defaultMarch string) string {
|
||||
for _, flag := range config.Target.CFlags {
|
||||
if strings.HasPrefix(flag, "-march=") {
|
||||
return flag[len("-march="):]
|
||||
}
|
||||
}
|
||||
return defaultMarch
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ func buildMuslAllTypes(arch, muslDir, outputBitsDir string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for _, line := range lines {
|
||||
lines := strings.SplitSeq(string(data), "\n")
|
||||
for line := range lines {
|
||||
if strings.HasPrefix(line, "TYPEDEF ") {
|
||||
matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line)
|
||||
value := matches[1]
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
|
||||
package builder
|
||||
|
||||
import "os"
|
||||
|
||||
func robustRename(oldpath, newpath string) error {
|
||||
return os.Rename(oldpath, newpath)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const robustRenameTimeout = 2 * time.Second
|
||||
|
||||
func robustRename(oldpath, newpath string) error {
|
||||
var bestErr error
|
||||
start := time.Now()
|
||||
nextSleep := time.Millisecond
|
||||
for {
|
||||
err := os.Rename(oldpath, newpath)
|
||||
if err == nil || !isEphemeralRenameError(err) {
|
||||
return err
|
||||
}
|
||||
if bestErr == nil {
|
||||
bestErr = err
|
||||
}
|
||||
if d := time.Since(start) + nextSleep; d >= robustRenameTimeout {
|
||||
return bestErr
|
||||
}
|
||||
time.Sleep(nextSleep)
|
||||
nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
|
||||
}
|
||||
}
|
||||
|
||||
func isEphemeralRenameError(err error) bool {
|
||||
var errno syscall.Errno
|
||||
if errors.As(err, &errno) {
|
||||
switch errno {
|
||||
case syscall.Errno(2), // ERROR_FILE_NOT_FOUND
|
||||
syscall.Errno(5), // ERROR_ACCESS_DENIED
|
||||
syscall.Errno(32): // ERROR_SHARING_VIOLATION
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+13
-3
@@ -501,8 +501,9 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
Align: section.Addralign,
|
||||
Type: memoryStack,
|
||||
})
|
||||
} else {
|
||||
// Regular .bss section.
|
||||
} else if section.Flags&elf.SHF_WRITE != 0 {
|
||||
// Regular .bss section. Zero-initialized RAM is always
|
||||
// writable, so require SHF_WRITE here.
|
||||
sections = append(sections, memorySection{
|
||||
Address: section.Addr,
|
||||
Size: section.Size,
|
||||
@@ -510,6 +511,11 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
Type: memoryBSS,
|
||||
})
|
||||
}
|
||||
// Other (non-writable) SHT_NOBITS sections are address-space
|
||||
// placeholders that occupy no RAM, such as the ESP linker
|
||||
// script's .irom_dummy / .rodata_dummy sections which reserve
|
||||
// the flash-mapped XIP virtual address ranges. They must not be
|
||||
// counted as bss/RAM usage.
|
||||
} else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_EXECINSTR != 0 {
|
||||
// .text
|
||||
sections = append(sections, memorySection{
|
||||
@@ -954,7 +960,11 @@ func findPackagePath(path string, packagePathMap map[string]string) (packagePath
|
||||
libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator))
|
||||
parts := strings.SplitN(libPath, string(os.PathSeparator), 2)
|
||||
packagePath = "C " + parts[0]
|
||||
filename = parts[1]
|
||||
if len(parts) > 1 {
|
||||
filename = parts[1]
|
||||
} else {
|
||||
filename = parts[0]
|
||||
}
|
||||
} else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) {
|
||||
packagePath = "C compiler-rt"
|
||||
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
|
||||
|
||||
@@ -42,16 +42,15 @@ func TestBinarySize(t *testing.T) {
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 3884, 280, 0, 2268},
|
||||
{"microbit", "examples/serial", 2852, 360, 8, 2272},
|
||||
{"wioterminal", "examples/pininterrupt", 7337, 1491, 116, 6912},
|
||||
{"hifive1b", "examples/echo", 3771, 309, 0, 2260},
|
||||
{"microbit", "examples/serial", 2832, 368, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 8065, 1663, 132, 7488},
|
||||
|
||||
// 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()
|
||||
|
||||
@@ -85,7 +84,6 @@ func TestSizeFull(t *testing.T) {
|
||||
pkgMatch := regexp.MustCompile(`^[a-z/]+$`) // example: "internal/task"
|
||||
|
||||
for _, target := range tests {
|
||||
target := target
|
||||
t.Run(target, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -99,7 +97,7 @@ func TestSizeFull(t *testing.T) {
|
||||
t.Fatal("could not read program size:", err)
|
||||
}
|
||||
for _, pkg := range sizes.sortedPackageNames() {
|
||||
if pkg == "(padding)" || pkg == "(unknown)" {
|
||||
if pkg == "(padding)" || pkg == "(unknown)" || pkg == "Go types" {
|
||||
// TODO: correctly attribute all unknown binary size.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func RunTool(tool string, args ...string) error {
|
||||
var cflag *C.char
|
||||
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
||||
defer C.free(buf)
|
||||
cflags := (*[1 << 10]*C.char)(unsafe.Pointer(buf))[:len(args):len(args)]
|
||||
cflags := unsafe.Slice((**C.char)(buf), len(args))
|
||||
for i, flag := range args {
|
||||
cflag := C.CString(flag)
|
||||
cflags[i] = cflag
|
||||
|
||||
+9
-3
@@ -116,18 +116,24 @@ func parseLLDErrors(text string) error {
|
||||
// This can happen in some cases like with CGo and //go:linkname tricker.
|
||||
if matches := regexp.MustCompile(`^ld.lld(-[0-9]+)?: error: undefined symbol: (.*)\n`).FindStringSubmatch(message); matches != nil {
|
||||
symbolName := matches[2]
|
||||
for _, line := range strings.Split(message, "\n") {
|
||||
for line := range strings.SplitSeq(message, "\n") {
|
||||
matches := regexp.MustCompile(`referenced by .* \(((.*):([0-9]+))\)`).FindStringSubmatch(line)
|
||||
if matches != nil {
|
||||
parsedError = true
|
||||
line, _ := strconv.Atoi(matches[3])
|
||||
// TODO: detect common mistakes like -gc=none?
|
||||
msg := "linker could not find symbol " + symbolName
|
||||
switch symbolName {
|
||||
case "runtime.alloc":
|
||||
msg = "object allocated on the heap with -gc=none"
|
||||
case "runtime.alloc_noheap":
|
||||
msg = "object allocated on the heap in //go:noheap function"
|
||||
}
|
||||
linkErrors = append(linkErrors, scanner.Error{
|
||||
Pos: token.Position{
|
||||
Filename: matches[2],
|
||||
Line: line,
|
||||
},
|
||||
Msg: "linker could not find symbol " + symbolName,
|
||||
Msg: msg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ func convertBinToUF2(input []byte, targetAddr uint32, uf2FamilyID string) ([]byt
|
||||
}
|
||||
bl.SetNumBlocks(len(blocks))
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
for i := range blocks {
|
||||
bl.SetBlockNo(i)
|
||||
bl.SetData(blocks[i])
|
||||
|
||||
|
||||
+10
-30
@@ -26,10 +26,6 @@ import (
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
// Function that's only defined in Go 1.22.
|
||||
var setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||
}
|
||||
|
||||
// cgoPackage holds all CGo-related information of a package.
|
||||
type cgoPackage struct {
|
||||
generated *ast.File
|
||||
@@ -44,7 +40,7 @@ type cgoPackage struct {
|
||||
tokenFiles map[string]*token.File
|
||||
definedGlobally map[string]ast.Node
|
||||
noescapingFuncs map[string]*noescapingFunc // #cgo noescape lines
|
||||
anonDecls map[interface{}]string
|
||||
anonDecls map[any]string
|
||||
cflags []string // CFlags from #cgo lines
|
||||
ldflags []string // LDFlags from #cgo lines
|
||||
visitedFiles map[string][]byte
|
||||
@@ -263,7 +259,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
tokenFiles: map[string]*token.File{},
|
||||
definedGlobally: map[string]ast.Node{},
|
||||
noescapingFuncs: map[string]*noescapingFunc{},
|
||||
anonDecls: map[interface{}]string{},
|
||||
anonDecls: map[any]string{},
|
||||
visitedFiles: map[string][]byte{},
|
||||
}
|
||||
|
||||
@@ -306,7 +302,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
// Find `import "C"` C fragments in the file.
|
||||
p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
|
||||
for i, f := range files {
|
||||
var cgoHeader string
|
||||
var cgoHeader strings.Builder
|
||||
for i := 0; i < len(f.Decls); i++ {
|
||||
decl := f.Decls[i]
|
||||
genDecl, ok := decl.(*ast.GenDecl)
|
||||
@@ -341,7 +337,8 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
// Iterate through all parts of the CGo header. Note that every //
|
||||
// line is a new comment.
|
||||
position := fset.Position(genDecl.Doc.Pos())
|
||||
fragment := fmt.Sprintf("# %d %#v\n", position.Line, position.Filename)
|
||||
var fragment strings.Builder
|
||||
fragment.WriteString(fmt.Sprintf("# %d %#v\n", position.Line, position.Filename))
|
||||
for _, comment := range genDecl.Doc.List {
|
||||
// Find all #cgo lines, extract and use their contents, and
|
||||
// replace the lines with spaces (to preserve locations).
|
||||
@@ -358,12 +355,13 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
} else { // comment
|
||||
c = " " + c[2:len(c)-2]
|
||||
}
|
||||
fragment += c + "\n"
|
||||
fragment.WriteString(c)
|
||||
fragment.WriteByte('\n')
|
||||
}
|
||||
cgoHeader += fragment
|
||||
cgoHeader.WriteString(fragment.String())
|
||||
}
|
||||
|
||||
p.cgoHeaders[i] = cgoHeader
|
||||
p.cgoHeaders[i] = cgoHeader.String()
|
||||
}
|
||||
|
||||
// Define CFlags that will be used while parsing the package.
|
||||
@@ -654,7 +652,6 @@ func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
|
||||
X: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "union",
|
||||
Obj: nil,
|
||||
},
|
||||
Sel: &ast.Ident{
|
||||
NamePos: pos,
|
||||
@@ -708,7 +705,6 @@ func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
|
||||
X: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: typeName,
|
||||
Obj: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -764,7 +760,6 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
|
||||
X: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "s",
|
||||
Obj: nil,
|
||||
},
|
||||
Sel: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
@@ -811,11 +806,6 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
|
||||
{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "s",
|
||||
Obj: &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: "s",
|
||||
Decl: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: &ast.StarExpr{
|
||||
@@ -823,7 +813,6 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
|
||||
X: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
Name: typeName,
|
||||
Obj: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -881,7 +870,6 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
|
||||
X: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "s",
|
||||
Obj: nil,
|
||||
},
|
||||
Sel: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
@@ -964,11 +952,6 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
|
||||
{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "s",
|
||||
Obj: &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: "s",
|
||||
Decl: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: &ast.StarExpr{
|
||||
@@ -976,7 +959,6 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
|
||||
X: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
Name: typeName,
|
||||
Obj: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -997,7 +979,6 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
|
||||
{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "value",
|
||||
Obj: nil,
|
||||
},
|
||||
},
|
||||
Type: bitfield.field.Type,
|
||||
@@ -1015,7 +996,6 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
|
||||
X: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
Name: "s",
|
||||
Obj: nil,
|
||||
},
|
||||
Sel: &ast.Ident{
|
||||
NamePos: bitfield.pos,
|
||||
@@ -1239,7 +1219,7 @@ func getPos(node ast.Node) token.Pos {
|
||||
// getUnnamedDeclName creates a name (with the given prefix) for the given C
|
||||
// declaration. This is used for structs, unions, and enums that are often
|
||||
// defined without a name and used in a typedef.
|
||||
func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
|
||||
func (p *cgoPackage) getUnnamedDeclName(prefix string, itf any) string {
|
||||
if name, ok := p.anonDecls[itf]; ok {
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
//go:build go1.22
|
||||
|
||||
package cgo
|
||||
|
||||
// Code specifically for Go 1.22.
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
func init() {
|
||||
setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||
f.FileStart = start
|
||||
f.FileEnd = end
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ func TestCGo(t *testing.T) {
|
||||
"flags",
|
||||
"const",
|
||||
} {
|
||||
name := name // avoid a race condition
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// Read the AST in memory.
|
||||
path := filepath.Join("testdata", name+".go")
|
||||
|
||||
+8
-66
@@ -130,7 +130,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
||||
// convert Go slice of strings to C array of strings.
|
||||
cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0))))
|
||||
defer C.free(cmdargsC)
|
||||
cmdargs := (*[1 << 16]*C.char)(cmdargsC)
|
||||
cmdargs := unsafe.Slice((**C.char)(cmdargsC), len(cflags))
|
||||
for i, cflag := range cflags {
|
||||
s := C.CString(cflag)
|
||||
cmdargs[i] = s
|
||||
@@ -160,7 +160,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
||||
pos := f.getClangLocationPosition(location, unit)
|
||||
f.addError(pos, severity+": "+spelling)
|
||||
}
|
||||
for i := 0; i < numDiagnostics; i++ {
|
||||
for i := range numDiagnostics {
|
||||
diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
|
||||
addDiagnostic(diagnostic)
|
||||
|
||||
@@ -190,7 +190,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
||||
// Sanity check. This should (hopefully) never trigger.
|
||||
panic("libclang: file contents was not loaded")
|
||||
}
|
||||
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
|
||||
data := unsafe.Slice((*byte)(unsafe.Pointer(rawData)), size)
|
||||
|
||||
// Hash the contents if it isn't hashed yet.
|
||||
if _, ok := f.visitedFiles[path]; !ok {
|
||||
@@ -217,10 +217,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
case C.CXCursor_FunctionDecl:
|
||||
cursorType := C.tinygo_clang_getCursorType(c)
|
||||
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Fun,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
exportName := name
|
||||
localName := name
|
||||
var stringSignature string
|
||||
@@ -258,7 +254,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "_Cgo_" + localName,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: &ast.FuncType{
|
||||
Func: pos,
|
||||
@@ -283,7 +278,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
Text: strings.Join(doc, "\n"),
|
||||
})
|
||||
}
|
||||
for i := 0; i < numArgs; i++ {
|
||||
for i := range numArgs {
|
||||
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
|
||||
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
|
||||
argType := C.clang_getArgType(cursorType, C.uint(i))
|
||||
@@ -295,11 +290,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
{
|
||||
NamePos: pos,
|
||||
Name: argName,
|
||||
Obj: &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: argName,
|
||||
Decl: decl,
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: f.makeDecayingASTType(argType, pos),
|
||||
@@ -315,7 +305,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
},
|
||||
}
|
||||
}
|
||||
obj.Decl = decl
|
||||
return decl, stringSignature
|
||||
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
||||
typ := f.makeASTRecordType(c, pos)
|
||||
@@ -325,39 +314,27 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
// Convert to a single-field struct type.
|
||||
typeExpr = f.makeUnionField(typ)
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
Name: typeName,
|
||||
}
|
||||
typeSpec := &ast.TypeSpec{
|
||||
Name: &ast.Ident{
|
||||
NamePos: typ.pos,
|
||||
Name: typeName,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: typeExpr,
|
||||
}
|
||||
obj.Decl = typeSpec
|
||||
return typeSpec, typ
|
||||
case C.CXCursor_TypedefDecl:
|
||||
typeName := "_Cgo_" + name
|
||||
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
Name: typeName,
|
||||
}
|
||||
typeSpec := &ast.TypeSpec{
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: typeName,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: f.makeASTType(underlyingType, pos),
|
||||
}
|
||||
if underlyingType.kind != C.CXType_Enum {
|
||||
typeSpec.Assign = pos
|
||||
}
|
||||
obj.Decl = typeSpec
|
||||
return typeSpec, nil
|
||||
case C.CXCursor_VarDecl:
|
||||
cursorType := C.tinygo_clang_getCursorType(c)
|
||||
@@ -376,19 +353,13 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
},
|
||||
},
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Type: typeExpr,
|
||||
}
|
||||
obj.Decl = valueSpec
|
||||
gen.Specs = append(gen.Specs, valueSpec)
|
||||
return gen, nil
|
||||
case C.CXCursor_MacroDefinition:
|
||||
@@ -405,26 +376,16 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
Lparen: token.NoPos,
|
||||
Rparen: token.NoPos,
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Con,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Values: []ast.Expr{expr},
|
||||
}
|
||||
obj.Decl = valueSpec
|
||||
gen.Specs = append(gen.Specs, valueSpec)
|
||||
return gen, nil
|
||||
case C.CXCursor_EnumDecl:
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
|
||||
// TODO: gc's CGo implementation uses types such as `uint32` for enums
|
||||
// instead of types such as C.int, which are used here.
|
||||
@@ -432,12 +393,10 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
},
|
||||
Assign: pos,
|
||||
Type: f.makeASTType(underlying, pos),
|
||||
}
|
||||
obj.Decl = typeSpec
|
||||
return typeSpec, nil
|
||||
case C.CXCursor_EnumConstantDecl:
|
||||
value := C.tinygo_clang_getEnumConstantDeclValue(c)
|
||||
@@ -452,19 +411,13 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
Lparen: token.NoPos,
|
||||
Rparen: token.NoPos,
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Con,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Values: []ast.Expr{expr},
|
||||
}
|
||||
obj.Decl = valueSpec
|
||||
gen.Specs = append(gen.Specs, valueSpec)
|
||||
return gen, nil
|
||||
default:
|
||||
@@ -581,7 +534,7 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||
|
||||
// Get the precise location in the source code. Used for uniquely identifying
|
||||
// source locations.
|
||||
func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) interface{} {
|
||||
func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) any {
|
||||
clangLocation := C.tinygo_clang_getCursorLocation(cursor)
|
||||
var file C.CXFile
|
||||
var line C.unsigned
|
||||
@@ -624,7 +577,7 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
|
||||
// now by reading the file from libclang.
|
||||
var size C.size_t
|
||||
sourcePtr := C.clang_getFileContents(tu, file, &size)
|
||||
source := ((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[:size:size]
|
||||
source := unsafe.Slice((*byte)(unsafe.Pointer(sourcePtr)), size)
|
||||
lines := []int{0}
|
||||
for i := 0; i < len(source)-1; i++ {
|
||||
if source[i] == '\n' {
|
||||
@@ -639,7 +592,8 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
|
||||
Package: f.Pos(0),
|
||||
Name: ast.NewIdent(p.packageName),
|
||||
}
|
||||
setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
|
||||
astFile.FileStart = f.Pos(0)
|
||||
astFile.FileEnd = f.Pos(int(size))
|
||||
p.cgoFiles = append(p.cgoFiles, astFile)
|
||||
}
|
||||
positionFile := p.tokenFiles[filename]
|
||||
@@ -956,22 +910,16 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
|
||||
}
|
||||
|
||||
// Construct an *ast.TypeSpec for this type.
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
Name: name,
|
||||
}
|
||||
spec := &ast.TypeSpec{
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: name,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: goName,
|
||||
},
|
||||
}
|
||||
obj.Decl = spec
|
||||
return spec
|
||||
}
|
||||
|
||||
@@ -1104,7 +1052,6 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
||||
pos: prevField.Names[0].NamePos,
|
||||
})
|
||||
prevField.Names[0].Name = bitfieldName
|
||||
prevField.Names[0].Obj.Name = bitfieldName
|
||||
}
|
||||
prevBitfield := &(*bitfieldList)[len(*bitfieldList)-1]
|
||||
prevBitfield.endBit = bitfieldOffset
|
||||
@@ -1121,11 +1068,6 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
||||
{
|
||||
NamePos: pos,
|
||||
Name: name,
|
||||
Obj: &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: name,
|
||||
Decl: field,
|
||||
},
|
||||
},
|
||||
}
|
||||
fieldList.List = append(fieldList.List, field)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include -I/usr/lib64/llvm19/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm19/include
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include -I/usr/lib64/llvm20/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm20/include
|
||||
|
||||
@@ -78,6 +78,7 @@ var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?plt`),
|
||||
re(`-f(no-)?rtti`),
|
||||
re(`-f(no-)?short-enums`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
|
||||
+4
-4
@@ -12,17 +12,17 @@ import "C"
|
||||
// C. It is useful if an API uses function pointers and you cannot pass a Go
|
||||
// pointer but only a C pointer.
|
||||
type refMap struct {
|
||||
refs map[unsafe.Pointer]interface{}
|
||||
refs map[unsafe.Pointer]any
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Put stores a value in the map. It can later be retrieved using Get. It must
|
||||
// be removed using Remove to avoid memory leaks.
|
||||
func (m *refMap) Put(v interface{}) unsafe.Pointer {
|
||||
func (m *refMap) Put(v any) unsafe.Pointer {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
if m.refs == nil {
|
||||
m.refs = make(map[unsafe.Pointer]interface{}, 1)
|
||||
m.refs = make(map[unsafe.Pointer]any, 1)
|
||||
}
|
||||
ref := C.malloc(1)
|
||||
m.refs[ref] = v
|
||||
@@ -31,7 +31,7 @@ func (m *refMap) Put(v interface{}) unsafe.Pointer {
|
||||
|
||||
// Get returns a stored value previously inserted with Put. Use the same
|
||||
// reference as you got from Put.
|
||||
func (m *refMap) Get(ref unsafe.Pointer) interface{} {
|
||||
func (m *refMap) Get(ref unsafe.Pointer) any {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
return m.refs[ref]
|
||||
|
||||
+22
-11
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -140,13 +141,7 @@ func (c *Config) GC() string {
|
||||
func (c *Config) NeedsStackObjects() bool {
|
||||
switch c.GC() {
|
||||
case "conservative", "custom", "precise", "boehm":
|
||||
for _, tag := range c.BuildTags() {
|
||||
if tag == "tinygo.wasm" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return slices.Contains(c.BuildTags(), "tinygo.wasm")
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -226,7 +221,7 @@ func (c *Config) StackSize() uint64 {
|
||||
|
||||
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
|
||||
func (c *Config) MaxStackAlloc() uint64 {
|
||||
if c.StackSize() > 32*1024 {
|
||||
if c.StackSize() >= 16*1024 {
|
||||
return 1024
|
||||
}
|
||||
|
||||
@@ -245,7 +240,7 @@ func (c *Config) RP2040BootPatch() bool {
|
||||
// Return a canonicalized architecture name, so we don't have to deal with arm*
|
||||
// vs thumb* vs arm64.
|
||||
func CanonicalArchName(triple string) string {
|
||||
arch := strings.Split(triple, "-")[0]
|
||||
arch, _, _ := strings.Cut(triple, "-")
|
||||
if arch == "arm64" {
|
||||
return "aarch64"
|
||||
}
|
||||
@@ -466,6 +461,22 @@ func (c *Config) LDFlags() []string {
|
||||
return ldflags
|
||||
}
|
||||
|
||||
// LinkerFlavor returns how the configured linker should be driven.
|
||||
// Usually this is derived from GOOS, but targets may override it explicitly.
|
||||
func (c *Config) LinkerFlavor() string {
|
||||
if c.Target.LinkerFlavor != "" {
|
||||
return c.Target.LinkerFlavor
|
||||
}
|
||||
switch c.GOOS() {
|
||||
case "windows":
|
||||
return "coff"
|
||||
case "darwin":
|
||||
return "darwin"
|
||||
default:
|
||||
return "gnu"
|
||||
}
|
||||
}
|
||||
|
||||
// ExtraFiles returns the list of extra files to be built and linked with the
|
||||
// executable. This can include extra C and assembly files.
|
||||
func (c *Config) ExtraFiles() []string {
|
||||
@@ -536,10 +547,10 @@ func (c *Config) Programmer() (method, openocdInterface string) {
|
||||
case "":
|
||||
// No configuration supplied.
|
||||
return c.Target.FlashMethod, c.Target.OpenOCDInterface
|
||||
case "openocd", "msd", "command":
|
||||
case "openocd", "msd", "command", "adb":
|
||||
// The -programmer flag only specifies the flash method.
|
||||
return c.Options.Programmer, c.Target.OpenOCDInterface
|
||||
case "bmp":
|
||||
case "bmp", "probe-rs":
|
||||
// The -programmer flag only specifies the flash method.
|
||||
return c.Options.Programmer, ""
|
||||
default:
|
||||
|
||||
+49
-54
@@ -3,6 +3,7 @@ package compileopts
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -21,50 +22,53 @@ var (
|
||||
// usually passed from the command line, but can also be passed in environment
|
||||
// variables for example.
|
||||
type Options struct {
|
||||
GOOS string // environment variable
|
||||
GOARCH string // environment variable
|
||||
GOARM string // environment variable (only used with GOARCH=arm)
|
||||
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
|
||||
Directory string // working dir, leave it unset to use the current working dir
|
||||
Target string
|
||||
BuildMode string // -buildmode flag
|
||||
Opt string
|
||||
GC string
|
||||
PanicStrategy string
|
||||
Scheduler string
|
||||
StackSize uint64 // goroutine stack size (if none could be automatically determined)
|
||||
Serial string
|
||||
Work bool // -work flag to print temporary build directory
|
||||
InterpTimeout time.Duration
|
||||
PrintIR bool
|
||||
DumpSSA bool
|
||||
VerifyIR bool
|
||||
SkipDWARF bool
|
||||
PrintCommands func(cmd string, args ...string) `json:"-"`
|
||||
Semaphore chan struct{} `json:"-"` // -p flag controls cap
|
||||
Debug bool
|
||||
Nobounds bool
|
||||
PrintSizes string
|
||||
PrintAllocs *regexp.Regexp // regexp string
|
||||
PrintStacks bool
|
||||
Tags []string
|
||||
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
||||
TestConfig TestConfig
|
||||
Programmer string
|
||||
OpenOCDCommands []string
|
||||
LLVMFeatures string
|
||||
Monitor bool
|
||||
BaudRate int
|
||||
Timeout time.Duration
|
||||
WITPackage string // pass through to wasm-tools component embed invocation
|
||||
WITWorld string // pass through to wasm-tools component embed -w option
|
||||
ExtLDFlags []string
|
||||
GOOS string // environment variable
|
||||
GOARCH string // environment variable
|
||||
GOARM string // environment variable (only used with GOARCH=arm)
|
||||
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
|
||||
Directory string // working dir, leave it unset to use the current working dir
|
||||
Target string
|
||||
BuildMode string // -buildmode flag
|
||||
Opt string
|
||||
GC string
|
||||
PanicStrategy string
|
||||
Scheduler string
|
||||
StackSize uint64 // goroutine stack size (if none could be automatically determined)
|
||||
Serial string
|
||||
Work bool // -work flag to print temporary build directory
|
||||
InterpTimeout time.Duration
|
||||
InterpMaxLoopIterations int
|
||||
PrintIR bool
|
||||
DumpSSA bool
|
||||
VerifyIR bool
|
||||
SkipDWARF bool
|
||||
PrintCommands func(cmd string, args ...string) `json:"-"`
|
||||
Semaphore chan struct{} `json:"-"` // -p flag controls cap
|
||||
Debug bool
|
||||
Nobounds bool
|
||||
PrintSizes string
|
||||
PrintAllocs *regexp.Regexp // regexp string
|
||||
PrintAllocsCover bool // emit allocs in go coverage tool format
|
||||
PrintStacks bool
|
||||
Tags []string
|
||||
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
||||
TestConfig TestConfig
|
||||
Programmer string
|
||||
OpenOCDCommands []string
|
||||
LLVMFeatures string
|
||||
Monitor bool
|
||||
BaudRate int
|
||||
Timeout time.Duration
|
||||
WITPackage string // pass through to wasm-tools component embed invocation
|
||||
WITWorld string // pass through to wasm-tools component embed -w option
|
||||
ExtLDFlags []string
|
||||
GoCompatibility bool // enable to check for Go version compatibility
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
func (o *Options) Verify() error {
|
||||
if o.BuildMode != "" {
|
||||
valid := isInArray(validBuildModeOptions, o.BuildMode)
|
||||
valid := slices.Contains(validBuildModeOptions, o.BuildMode)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid buildmode option '%s': valid values are %s`,
|
||||
o.BuildMode,
|
||||
@@ -72,7 +76,7 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
}
|
||||
if o.GC != "" {
|
||||
valid := isInArray(validGCOptions, o.GC)
|
||||
valid := slices.Contains(validGCOptions, o.GC)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid gc option '%s': valid values are %s`,
|
||||
o.GC,
|
||||
@@ -81,7 +85,7 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
|
||||
if o.Scheduler != "" {
|
||||
valid := isInArray(validSchedulerOptions, o.Scheduler)
|
||||
valid := slices.Contains(validSchedulerOptions, o.Scheduler)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid scheduler option '%s': valid values are %s`,
|
||||
o.Scheduler,
|
||||
@@ -90,7 +94,7 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
|
||||
if o.Serial != "" {
|
||||
valid := isInArray(validSerialOptions, o.Serial)
|
||||
valid := slices.Contains(validSerialOptions, o.Serial)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid serial option '%s': valid values are %s`,
|
||||
o.Serial,
|
||||
@@ -99,7 +103,7 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
|
||||
if o.PrintSizes != "" {
|
||||
valid := isInArray(validPrintSizeOptions, o.PrintSizes)
|
||||
valid := slices.Contains(validPrintSizeOptions, o.PrintSizes)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid size option '%s': valid values are %s`,
|
||||
o.PrintSizes,
|
||||
@@ -108,7 +112,7 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
|
||||
if o.PanicStrategy != "" {
|
||||
valid := isInArray(validPanicStrategyOptions, o.PanicStrategy)
|
||||
valid := slices.Contains(validPanicStrategyOptions, o.PanicStrategy)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid panic option '%s': valid values are %s`,
|
||||
o.PanicStrategy,
|
||||
@@ -117,19 +121,10 @@ func (o *Options) Verify() error {
|
||||
}
|
||||
|
||||
if o.Opt != "" {
|
||||
if !isInArray(validOptOptions, o.Opt) {
|
||||
if !slices.Contains(validOptOptions, o.Opt) {
|
||||
return fmt.Errorf("invalid -opt=%s: valid values are %s", o.Opt, strings.Join(validOptOptions, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isInArray(arr []string, item string) bool {
|
||||
for _, i := range arr {
|
||||
if i == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+24
-1
@@ -24,6 +24,7 @@ import (
|
||||
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
||||
type TargetSpec struct {
|
||||
Inherits []string `json:"inherits,omitempty"`
|
||||
InheritableOnly bool `json:"inheritable-only"` // this target is only meant to be inherited from, not used directly
|
||||
Triple string `json:"llvm-target,omitempty"`
|
||||
CPU string `json:"cpu,omitempty"`
|
||||
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
|
||||
@@ -37,7 +38,8 @@ type TargetSpec struct {
|
||||
Scheduler string `json:"scheduler,omitempty"`
|
||||
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
|
||||
Linker string `json:"linker,omitempty"`
|
||||
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
|
||||
LinkerFlavor string `json:"linker-flavor,omitempty"` // how to drive the configured linker (for example: gnu, coff, darwin)
|
||||
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
|
||||
Libc string `json:"libc,omitempty"`
|
||||
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
|
||||
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
|
||||
@@ -63,6 +65,10 @@ type TargetSpec struct {
|
||||
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
|
||||
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
|
||||
JLinkDevice string `json:"jlink-device,omitempty"`
|
||||
ADBPreCommands []string `json:"adb-pre-commands,omitempty"`
|
||||
ADBPushRemote string `json:"adb-push-remote,omitempty"`
|
||||
ADBPostCommands []string `json:"adb-post-commands,omitempty"`
|
||||
ProbeRSChip string `json:"probe-rs-chip,omitempty"`
|
||||
CodeModel string `json:"code-model,omitempty"`
|
||||
RelocationModel string `json:"relocation-model,omitempty"`
|
||||
WITPackage string `json:"wit-package,omitempty"`
|
||||
@@ -148,6 +154,11 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
||||
|
||||
// resolveInherits loads inherited targets, recursively.
|
||||
func (spec *TargetSpec) resolveInherits() error {
|
||||
// Save InheritableOnly before resolving, since it must not propagate
|
||||
// from parent to child (a board target should not become inheritable-only
|
||||
// just because its parent processor target is).
|
||||
inheritableOnly := spec.InheritableOnly
|
||||
|
||||
// First create a new spec with all the inherited properties.
|
||||
newSpec := &TargetSpec{}
|
||||
for _, name := range spec.Inherits {
|
||||
@@ -173,6 +184,9 @@ func (spec *TargetSpec) resolveInherits() error {
|
||||
}
|
||||
*spec = *newSpec
|
||||
|
||||
// Restore InheritableOnly from the original spec, not from parents.
|
||||
spec.InheritableOnly = inheritableOnly
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -239,10 +253,17 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(dir, entry.Name())
|
||||
|
||||
spec, err := LoadTarget(&Options{Target: path})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list target: %w", err)
|
||||
}
|
||||
|
||||
if spec.InheritableOnly {
|
||||
// Skip targets that are only meant to be inherited from, not used directly.
|
||||
continue
|
||||
}
|
||||
|
||||
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
|
||||
// This doesn't look like a regular target file, but rather like
|
||||
// a parent target (such as targets/cortex-m.json).
|
||||
@@ -465,6 +486,8 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"--no-insert-timestamp",
|
||||
"--no-dynamicbase",
|
||||
)
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/runtime_windows.c")
|
||||
case "wasm", "wasip1", "wasip2":
|
||||
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
|
||||
default:
|
||||
|
||||
@@ -23,6 +23,37 @@ func TestLoadTarget(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTargetSpecs_InheritableOnlyTargetsExcluded(t *testing.T) {
|
||||
specs, err := GetTargetSpecs()
|
||||
if err != nil {
|
||||
t.Fatal("GetTargetSpecs failed:", err)
|
||||
}
|
||||
|
||||
// Inheritable-only processor-level targets should not appear in the listing.
|
||||
inheritableOnlyTargets := []string{"esp32", "esp32c3", "esp32s3", "esp8266", "rp2040", "rp2350", "rp2350b"}
|
||||
for _, name := range inheritableOnlyTargets {
|
||||
if _, ok := specs[name]; ok {
|
||||
t.Errorf("inheritable-only target %q should not appear in GetTargetSpecs", name)
|
||||
}
|
||||
}
|
||||
|
||||
// Board targets that inherit from inheritable-only targets should still appear.
|
||||
boardTargets := []string{"esp32-coreboard-v2", "pico"}
|
||||
for _, name := range boardTargets {
|
||||
if _, ok := specs[name]; !ok {
|
||||
t.Errorf("board target %q should appear in GetTargetSpecs", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTarget_InheritableOnlyTargetStillLoadable(t *testing.T) {
|
||||
// Inheritable-only targets should still be loadable directly (for building).
|
||||
_, err := LoadTarget(&Options{Target: "esp32"})
|
||||
if err != nil {
|
||||
t.Errorf("LoadTarget should still load inheritable-only target esp32: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrideProperties(t *testing.T) {
|
||||
baseAutoStackSize := true
|
||||
base := &TargetSpec{
|
||||
@@ -81,3 +112,52 @@ func TestOverrideProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestConfigLinkerFlavor(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
target *TargetSpec
|
||||
goos string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "default gnu",
|
||||
target: &TargetSpec{},
|
||||
goos: "linux",
|
||||
want: "gnu",
|
||||
},
|
||||
{
|
||||
name: "default coff",
|
||||
target: &TargetSpec{},
|
||||
goos: "windows",
|
||||
want: "coff",
|
||||
},
|
||||
{
|
||||
name: "default darwin",
|
||||
target: &TargetSpec{},
|
||||
goos: "darwin",
|
||||
want: "darwin",
|
||||
},
|
||||
{
|
||||
name: "target override",
|
||||
target: &TargetSpec{
|
||||
LinkerFlavor: "coff",
|
||||
},
|
||||
goos: "linux",
|
||||
want: "coff",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.target.GOOS = tc.goos
|
||||
config := &Config{
|
||||
Options: &Options{},
|
||||
Target: tc.target,
|
||||
}
|
||||
if got := config.LinkerFlavor(); got != tc.want {
|
||||
t.Fatalf("LinkerFlavor() = %q, want %q", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+22
-9
@@ -241,24 +241,37 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
|
||||
}
|
||||
}
|
||||
|
||||
// Put the fault block at the end of the function and the next block at the
|
||||
// current insert position.
|
||||
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||
faultBlock := b.getRuntimeAssertBlock(blockPrefix, assertFunc)
|
||||
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
|
||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
|
||||
|
||||
// Now branch to the out-of-bounds or the regular block.
|
||||
b.CreateCondBr(assert, faultBlock, nextBlock)
|
||||
|
||||
// Fail: the assert triggered so panic.
|
||||
b.SetInsertPointAtEnd(faultBlock)
|
||||
b.createRuntimeCall(assertFunc, nil, "")
|
||||
b.CreateUnreachable()
|
||||
|
||||
// Ok: assert didn't trigger so continue normally.
|
||||
b.SetInsertPointAtEnd(nextBlock)
|
||||
}
|
||||
|
||||
func (b *builder) getRuntimeAssertBlock(blockPrefix, assertFunc string) llvm.BasicBlock {
|
||||
if b.runtimeAssertBlocks == nil {
|
||||
b.runtimeAssertBlocks = make(map[string]llvm.BasicBlock)
|
||||
}
|
||||
if block := b.runtimeAssertBlocks[assertFunc]; !block.IsNil() {
|
||||
return block
|
||||
}
|
||||
savedBlock := b.GetInsertBlock()
|
||||
block := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||
b.runtimeAssertBlocks[assertFunc] = block
|
||||
b.SetInsertPointAtEnd(block)
|
||||
if b.hasDeferFrame() {
|
||||
b.createFaultCheckpoint()
|
||||
}
|
||||
b.createRuntimeCall(assertFunc, nil, "")
|
||||
b.CreateUnreachable()
|
||||
b.SetInsertPointAtEnd(savedBlock)
|
||||
return block
|
||||
}
|
||||
|
||||
// extendInteger extends the value to at least targetType using a zero or sign
|
||||
// extend. The resulting value is not truncated: it may still be bigger than
|
||||
// targetType.
|
||||
|
||||
@@ -32,6 +32,9 @@ const (
|
||||
// Whether this is a full or partial Go parameter (int, slice, etc).
|
||||
// The extra context parameter is not a Go parameter.
|
||||
paramIsGoParam = 1 << iota
|
||||
|
||||
// Whether this is a readonly parameter (for example, a string pointer).
|
||||
paramIsReadonly
|
||||
)
|
||||
|
||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
||||
@@ -167,6 +170,7 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
||||
continue
|
||||
}
|
||||
suffix := strconv.Itoa(i)
|
||||
isString := false
|
||||
if goType != nil {
|
||||
// Try to come up with a good suffix for this struct field,
|
||||
// depending on which Go type it's based on.
|
||||
@@ -183,12 +187,16 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
|
||||
suffix = []string{"r", "i"}[i]
|
||||
case types.String:
|
||||
suffix = []string{"data", "len"}[i]
|
||||
isString = true
|
||||
}
|
||||
case *types.Signature:
|
||||
suffix = []string{"context", "funcptr"}[i]
|
||||
}
|
||||
}
|
||||
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||
if isString {
|
||||
subInfos[0].flags |= paramIsReadonly
|
||||
}
|
||||
paramInfos = append(paramInfos, subInfos...)
|
||||
}
|
||||
return paramInfos
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ func (b *builder) createChanSend(instr *ssa.Send) {
|
||||
channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op")
|
||||
|
||||
// Do the send.
|
||||
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "")
|
||||
b.createRuntimeInvoke("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "")
|
||||
|
||||
// End the lifetime of the allocas.
|
||||
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
||||
@@ -101,7 +101,7 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
||||
|
||||
// createChanClose closes the given channel.
|
||||
func (b *builder) createChanClose(ch llvm.Value) {
|
||||
b.createRuntimeCall("chanClose", []llvm.Value{ch}, "")
|
||||
b.createRuntimeInvoke("chanClose", []llvm.Value{ch}, "")
|
||||
}
|
||||
|
||||
// createSelect emits all IR necessary for a select statements. That's a
|
||||
|
||||
+172
-51
@@ -90,8 +90,10 @@ type compilerContext struct {
|
||||
astComments map[string]*ast.CommentGroup
|
||||
embedGlobals map[string][]*loader.EmbedFile
|
||||
pkg *types.Package
|
||||
packageDir string // directory for this package
|
||||
loaderPkg *loader.Package // current package being compiled (for AST access)
|
||||
packageDir string // directory for this package
|
||||
runtimePkg *types.Package
|
||||
localTypeNames typeutil.Map // *types.Named (synthetic local from generic instantiation) -> string
|
||||
}
|
||||
|
||||
// newCompilerContext returns a new compiler context ready for use, most
|
||||
@@ -152,10 +154,12 @@ type builder struct {
|
||||
llvmFnType llvm.Type
|
||||
llvmFn llvm.Value
|
||||
info functionInfo
|
||||
locals map[ssa.Value]llvm.Value // local variables
|
||||
blockEntries map[*ssa.BasicBlock]llvm.BasicBlock // a *ssa.BasicBlock may be split up
|
||||
blockExits map[*ssa.BasicBlock]llvm.BasicBlock // these are the exit blocks
|
||||
locals map[ssa.Value]llvm.Value // local variables
|
||||
blockInfo []blockInfo
|
||||
currentBlock *ssa.BasicBlock
|
||||
currentBlockInfo *blockInfo
|
||||
tarjanStack []uint
|
||||
tarjanIndex uint
|
||||
phis []phiNode
|
||||
deferPtr llvm.Value
|
||||
deferFrame llvm.Value
|
||||
@@ -165,7 +169,7 @@ type builder struct {
|
||||
dilocals map[*types.Var]llvm.Metadata
|
||||
initInlinedAt llvm.Metadata // fake inlinedAt position
|
||||
initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations
|
||||
allDeferFuncs []interface{}
|
||||
allDeferFuncs []any
|
||||
deferFuncs map[*ssa.Function]int
|
||||
deferInvokeFuncs map[string]int
|
||||
deferClosureFuncs map[*ssa.Function]int
|
||||
@@ -174,6 +178,9 @@ type builder struct {
|
||||
deferBuiltinFuncs map[ssa.Value]deferBuiltin
|
||||
runDefersBlock []llvm.BasicBlock
|
||||
afterDefersBlock []llvm.BasicBlock
|
||||
|
||||
runtimeAssertBlocks map[string]llvm.BasicBlock
|
||||
interfaceAssertBlock llvm.BasicBlock
|
||||
}
|
||||
|
||||
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
|
||||
@@ -187,11 +194,22 @@ func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *bu
|
||||
info: c.getFunctionInfo(f),
|
||||
locals: make(map[ssa.Value]llvm.Value),
|
||||
dilocals: make(map[*types.Var]llvm.Metadata),
|
||||
blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
||||
blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock),
|
||||
}
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
// entry is the LLVM basic block corresponding to the start of this *ssa.Block.
|
||||
entry llvm.BasicBlock
|
||||
|
||||
// exit is the LLVM basic block corresponding to the end of this *ssa.Block.
|
||||
// It will be different than entry if any of the block's instructions contain internal branches.
|
||||
exit llvm.BasicBlock
|
||||
|
||||
// tarjan holds state for applying Tarjan's strongly connected components algorithm to the CFG.
|
||||
// This is used by defer.go to determine whether to stack- or heap-allocate defer data.
|
||||
tarjan tarjanNode
|
||||
}
|
||||
|
||||
type deferBuiltin struct {
|
||||
callName string
|
||||
pos token.Pos
|
||||
@@ -281,12 +299,18 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
||||
c.packageDir = pkg.OriginalDir()
|
||||
c.embedGlobals = pkg.EmbedGlobals
|
||||
c.pkg = pkg.Pkg
|
||||
c.loaderPkg = pkg
|
||||
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
|
||||
c.program = ssaPkg.Prog
|
||||
|
||||
// Convert AST to SSA.
|
||||
ssaPkg.Build()
|
||||
|
||||
// Assign names to function-local named types before compiling the
|
||||
// package, so that types declared in different functions (or in
|
||||
// different instantiations of a generic function) do not collide.
|
||||
c.scanLocalTypes(ssaPkg)
|
||||
|
||||
// Initialize debug information.
|
||||
if c.Debug {
|
||||
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
|
||||
@@ -301,9 +325,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
||||
// Load comments such as //go:extern on globals.
|
||||
c.loadASTComments(pkg)
|
||||
|
||||
// Predeclare the runtime.alloc function, which is used by the wordpack
|
||||
// functionality.
|
||||
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
|
||||
if c.NeedsStackObjects {
|
||||
// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
|
||||
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
|
||||
@@ -849,10 +870,9 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
}
|
||||
// Create the function definition.
|
||||
b := newBuilder(c, irbuilder, member)
|
||||
if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok {
|
||||
if ok := b.defineMathOp(); ok {
|
||||
// The body of this function (if there is one) is ignored and
|
||||
// replaced with a LLVM intrinsic call.
|
||||
b.defineMathOp()
|
||||
continue
|
||||
}
|
||||
if ok := b.defineMathBitsIntrinsic(); ok {
|
||||
@@ -860,6 +880,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
// with a LLVM intrinsic.
|
||||
continue
|
||||
}
|
||||
if ok := b.defineCryptoIntrinsic(); ok {
|
||||
// Body of this function was replaced
|
||||
continue
|
||||
}
|
||||
if member.Blocks == nil {
|
||||
// Try to define this as an intrinsic function.
|
||||
b.defineIntrinsicFunction()
|
||||
@@ -1220,14 +1244,29 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
||||
// intrinsic (like an atomic operation). Create the entry block
|
||||
// manually.
|
||||
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
||||
} else {
|
||||
for _, block := range b.fn.DomPreorder() {
|
||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||
b.blockEntries[block] = llvmBlock
|
||||
b.blockExits[block] = llvmBlock
|
||||
// Intrinsics may create internal branches (e.g. nil checks).
|
||||
// They will attempt to access b.currentBlockInfo to update the exit block.
|
||||
// Create some fake block info for them to access.
|
||||
blockInfo := []blockInfo{
|
||||
{
|
||||
entry: entryBlock,
|
||||
exit: entryBlock,
|
||||
},
|
||||
}
|
||||
b.blockInfo = blockInfo
|
||||
b.currentBlockInfo = &blockInfo[0]
|
||||
} else {
|
||||
blocks := b.fn.Blocks
|
||||
blockInfo := make([]blockInfo, len(blocks))
|
||||
for _, block := range b.fn.DomPreorder() {
|
||||
info := &blockInfo[block.Index]
|
||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||
info.entry = llvmBlock
|
||||
info.exit = llvmBlock
|
||||
}
|
||||
b.blockInfo = blockInfo
|
||||
// Normal functions have an entry block.
|
||||
entryBlock = b.blockEntries[b.fn.Blocks[0]]
|
||||
entryBlock = blockInfo[0].entry
|
||||
}
|
||||
b.SetInsertPointAtEnd(entryBlock)
|
||||
|
||||
@@ -1323,8 +1362,9 @@ func (b *builder) createFunction() {
|
||||
if b.DumpSSA {
|
||||
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
||||
}
|
||||
b.SetInsertPointAtEnd(b.blockEntries[block])
|
||||
b.currentBlock = block
|
||||
b.currentBlockInfo = &b.blockInfo[block.Index]
|
||||
b.SetInsertPointAtEnd(b.currentBlockInfo.entry)
|
||||
for _, instr := range block.Instrs {
|
||||
if instr, ok := instr.(*ssa.DebugRef); ok {
|
||||
if !b.Debug {
|
||||
@@ -1384,7 +1424,7 @@ func (b *builder) createFunction() {
|
||||
block := phi.ssa.Block()
|
||||
for i, edge := range phi.ssa.Edges {
|
||||
llvmVal := b.getValue(edge, getPos(phi.ssa))
|
||||
llvmBlock := b.blockExits[block.Preds[i]]
|
||||
llvmBlock := b.blockInfo[block.Preds[i].Index].exit
|
||||
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
||||
}
|
||||
}
|
||||
@@ -1498,11 +1538,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
case *ssa.If:
|
||||
cond := b.getValue(instr.Cond, getPos(instr))
|
||||
block := instr.Block()
|
||||
blockThen := b.blockEntries[block.Succs[0]]
|
||||
blockElse := b.blockEntries[block.Succs[1]]
|
||||
blockThen := b.blockInfo[block.Succs[0].Index].entry
|
||||
blockElse := b.blockInfo[block.Succs[1].Index].entry
|
||||
b.CreateCondBr(cond, blockThen, blockElse)
|
||||
case *ssa.Jump:
|
||||
blockJump := b.blockEntries[instr.Block().Succs[0]]
|
||||
blockJump := b.blockInfo[instr.Block().Succs[0].Index].entry
|
||||
b.CreateBr(blockJump)
|
||||
case *ssa.MapUpdate:
|
||||
m := b.getValue(instr.Map, getPos(instr))
|
||||
@@ -1570,7 +1610,8 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
|
||||
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
||||
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
||||
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
|
||||
elemLayout := b.createObjectLayout(elemType, pos)
|
||||
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize, elemLayout}, "append.new")
|
||||
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
|
||||
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
||||
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
||||
@@ -1652,13 +1693,41 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
case "copy":
|
||||
dst := argValues[0]
|
||||
src := argValues[1]
|
||||
// Fetch the lengths.
|
||||
dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen")
|
||||
srcLen := b.CreateExtractValue(src, 1, "copy.srcLen")
|
||||
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
|
||||
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
|
||||
// Find the minimum of the lengths.
|
||||
minFuncName := "llvm.umin.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||
minFunc := b.mod.NamedFunction(minFuncName)
|
||||
if minFunc.IsNil() {
|
||||
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType, b.uintptrType}, false)
|
||||
minFunc = llvm.AddFunction(b.mod, minFuncName, fnType)
|
||||
}
|
||||
minLen := b.CreateCall(minFunc.GlobalValueType(), minFunc, []llvm.Value{dstLen, srcLen}, "copy.n")
|
||||
// Multiply the length by the element size.
|
||||
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
||||
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
||||
return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
|
||||
// NOTE: This is also NSW when uintptr is int, but we can only choose one through the C API?
|
||||
size := b.CreateNUWMul(minLen, elemSize, "copy.size")
|
||||
// Fetch the pointers.
|
||||
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstPtr")
|
||||
srcBuf := b.CreateExtractValue(src, 0, "copy.srcPtr")
|
||||
// Create a memcpy.
|
||||
call := b.createMemCopy("memmove", dstBuf, srcBuf, size)
|
||||
align := b.targetData.ABITypeAlignment(elemType)
|
||||
if align > 1 {
|
||||
// Apply the type's alignment to the arguments.
|
||||
// LLVM sometimes turns constant-length moves into loads and stores.
|
||||
// It may use this alignment for the created loads and stores.
|
||||
alignAttr := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))
|
||||
call.AddCallSiteAttribute(1, alignAttr)
|
||||
call.AddCallSiteAttribute(2, alignAttr)
|
||||
}
|
||||
// Extend and return the copied length.
|
||||
if b.targetData.TypeAllocSize(minLen.Type()) < b.targetData.TypeAllocSize(b.intType) {
|
||||
minLen = b.CreateZExt(minLen, b.intType, "copy.n.zext")
|
||||
}
|
||||
return minLen, nil
|
||||
case "delete":
|
||||
m := argValues[0]
|
||||
key := argValues[1]
|
||||
@@ -1686,20 +1755,66 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
return llvmLen, nil
|
||||
case "min", "max":
|
||||
// min and max builtins, added in Go 1.21.
|
||||
// We can simply reuse the existing binop comparison code, which has all
|
||||
// the edge cases figured out already.
|
||||
tok := token.LSS
|
||||
if callName == "max" {
|
||||
tok = token.GTR
|
||||
}
|
||||
result := argValues[0]
|
||||
typ := argTypes[0]
|
||||
for _, arg := range argValues[1:] {
|
||||
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
|
||||
if err != nil {
|
||||
return result, err
|
||||
// Find the corresponding intrinsic name.
|
||||
ty := argTypes[0].Underlying().(*types.Basic)
|
||||
llvmType := b.getLLVMType(ty)
|
||||
info := ty.Info()
|
||||
var prefix, delimeter, typeName string
|
||||
if info&types.IsInteger != 0 {
|
||||
// This is an integer value.
|
||||
// Use the LLVM int min/max intrinsics.
|
||||
prefix = "llvm.s"
|
||||
if info&types.IsUnsigned != 0 {
|
||||
prefix = "llvm.u"
|
||||
}
|
||||
result = b.CreateSelect(cmp, result, arg, "")
|
||||
delimeter = ".i"
|
||||
typeName = strconv.Itoa(llvmType.IntTypeWidth())
|
||||
} else {
|
||||
switch ty.Kind() {
|
||||
case types.String:
|
||||
// Strings do not have an equivalent intrinsic.
|
||||
// Implement with compares and selects.
|
||||
tok := token.LSS
|
||||
if callName == "max" {
|
||||
tok = token.GTR
|
||||
}
|
||||
result := argValues[0]
|
||||
typ := argTypes[0]
|
||||
for _, arg := range argValues[1:] {
|
||||
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = b.CreateSelect(cmp, result, arg, "")
|
||||
}
|
||||
return result, nil
|
||||
case types.Float32:
|
||||
typeName = "f32"
|
||||
case types.Float64:
|
||||
typeName = "f64"
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(pos, "todo: min/max: unknown type")
|
||||
}
|
||||
// There are a few edge cases with floating point min/max:
|
||||
// min(-0.0, +0.0) = -0.0
|
||||
// min(NaN, number) = NaN
|
||||
// The llvm.minimum.*/llvm.maximum.* intrinsics match this behavior.
|
||||
// Neither Go nor LLVM defines the bit representation of resulting NaNs.
|
||||
prefix = "llvm."
|
||||
delimeter = "imum."
|
||||
}
|
||||
intrinsicName := prefix + callName + delimeter + typeName
|
||||
// Find or create the intrinsic.
|
||||
llvmFn := b.mod.NamedFunction(intrinsicName)
|
||||
if llvmFn.IsNil() {
|
||||
fnType := llvm.FunctionType(llvmType, []llvm.Type{llvmType, llvmType}, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, intrinsicName, fnType)
|
||||
}
|
||||
// Call the intrinsic repeatedly to merge the arguments.
|
||||
callType := llvmFn.GlobalValueType()
|
||||
result := argValues[0]
|
||||
for _, arg := range argValues[1:] {
|
||||
result = b.CreateCall(callType, llvmFn, []llvm.Value{result, arg}, "")
|
||||
}
|
||||
return result, nil
|
||||
case "panic":
|
||||
@@ -1780,6 +1895,12 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
// not of the current function.
|
||||
useParentFrame = 1
|
||||
}
|
||||
// Prevent inlining of functions that call recover(), matching the
|
||||
// Go compiler's behavior. If this function were inlined into a
|
||||
// deferred function, recover() would incorrectly succeed because
|
||||
// the inlined code runs in the deferred function's context.
|
||||
noinline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0)
|
||||
b.llvmFn.AddFunctionAttr(noinline)
|
||||
return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil
|
||||
case "ssa:wrapnilchk":
|
||||
// TODO: do an actual nil check?
|
||||
@@ -1872,10 +1993,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return b.emitSV64Call(instr.Args, getPos(instr))
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
|
||||
case (strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall")) && name != "syscall.SyscallN":
|
||||
if b.GOOS != "darwin" {
|
||||
return b.createSyscall(instr)
|
||||
}
|
||||
case name == "syscall.syscalln":
|
||||
if b.GOOS == "windows" {
|
||||
return b.createSyscalln(instr)
|
||||
}
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
case name == "runtime.supportsRecover":
|
||||
@@ -2031,13 +2156,10 @@ func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 {
|
||||
if elementSize == 0 {
|
||||
elementSize = 1
|
||||
}
|
||||
maxSize := maxPointerValue / elementSize
|
||||
|
||||
// len(slice) is an int. Make sure the length remains small enough to fit in
|
||||
// an int.
|
||||
if maxSize > maxIntegerValue {
|
||||
maxSize = maxIntegerValue
|
||||
}
|
||||
maxSize := min(
|
||||
// len(slice) is an int. Make sure the length remains small enough to fit in
|
||||
// an int.
|
||||
maxPointerValue/elementSize, maxIntegerValue)
|
||||
|
||||
return maxSize
|
||||
}
|
||||
@@ -2064,9 +2186,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
}
|
||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||
layoutValue := b.createObjectLayout(typ, expr.Pos())
|
||||
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
|
||||
align := b.targetData.ABITypeAlignment(typ)
|
||||
buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
|
||||
buf := b.createAlloc(sizeValue, layoutValue, align, expr.Comment)
|
||||
return buf, nil
|
||||
} else {
|
||||
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
|
||||
@@ -2296,7 +2417,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
}
|
||||
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
||||
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
|
||||
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
|
||||
slicePtr := b.createAlloc(sliceSize, layoutValue, 0, "makeslice.buf")
|
||||
slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
|
||||
|
||||
// Extend or truncate if necessary. This is safe as we've already done
|
||||
|
||||
@@ -50,6 +50,7 @@ func TestCompiler(t *testing.T) {
|
||||
{"channel.go", "", ""},
|
||||
{"gc.go", "", ""},
|
||||
{"zeromap.go", "", ""},
|
||||
{"generics.go", "", ""},
|
||||
}
|
||||
if goMinor >= 20 {
|
||||
tests = append(tests, testCase{"go1.20.go", "", ""})
|
||||
@@ -187,9 +188,9 @@ func TestCompilerErrors(t *testing.T) {
|
||||
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: "))
|
||||
for line := range strings.SplitSeq(errorsFileString, "\n") {
|
||||
if after, ok := strings.CutPrefix(line, "// ERROR: "); ok {
|
||||
expectedErrors = append(expectedErrors, after)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+131
-40
@@ -60,10 +60,6 @@ func (b *builder) deferInitFunc() {
|
||||
b.deferExprFuncs = make(map[ssa.Value]int)
|
||||
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
|
||||
|
||||
// Create defer list pointer.
|
||||
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
|
||||
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
|
||||
|
||||
if b.hasDeferFrame() {
|
||||
// Set up the defer frame with the current stack pointer.
|
||||
// This assumes that the stack pointer doesn't move outside of the
|
||||
@@ -73,12 +69,22 @@ func (b *builder) deferInitFunc() {
|
||||
// in the setjmp-like inline assembly.
|
||||
deferFrameType := b.getLLVMRuntimeType("deferFrame")
|
||||
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
|
||||
// The field index must match the DeferPtr field in runtime.deferFrame,
|
||||
// defined in src/runtime/panic.go.
|
||||
b.deferPtr = b.CreateInBoundsGEP(deferFrameType, b.deferFrame, []llvm.Value{
|
||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(b.ctx.Int32Type(), 6, false), // DeferPtr field
|
||||
}, "deferPtr")
|
||||
stackPointer := b.readStackPointer()
|
||||
b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "")
|
||||
|
||||
// Create the landing pad block, which is where control transfers after
|
||||
// a panic.
|
||||
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad")
|
||||
} else {
|
||||
// Create defer list pointer.
|
||||
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
|
||||
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +106,7 @@ func (b *builder) createLandingPad() {
|
||||
|
||||
// Continue at the 'recover' block, which returns to the parent in an
|
||||
// appropriate way.
|
||||
b.CreateBr(b.blockEntries[b.fn.Recover])
|
||||
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
|
||||
}
|
||||
|
||||
// Create a checkpoint (similar to setjmp). This emits inline assembly that
|
||||
@@ -110,8 +116,8 @@ func (b *builder) createLandingPad() {
|
||||
func (b *builder) createCheckpoint(ptr llvm.Value) llvm.Value {
|
||||
// Construct inline assembly equivalents of setjmp.
|
||||
// The assembly works as follows:
|
||||
// * All registers (both callee-saved and caller saved) are clobbered
|
||||
// after the inline assembly returns.
|
||||
// * Registers are either clobbered or, on 386, saved for longjmp to
|
||||
// restore if the ABI requires them to survive calls.
|
||||
// * The assembly stores the address just past the end of the assembly
|
||||
// into the jump buffer.
|
||||
// * The return value (eax, rax, r0, etc) is set to zero in the inline
|
||||
@@ -124,8 +130,12 @@ func (b *builder) createCheckpoint(ptr llvm.Value) llvm.Value {
|
||||
asmString = `
|
||||
xorl %eax, %eax
|
||||
movl $$1f, 4(%ebx)
|
||||
movl %ebx, 8(%ebx)
|
||||
movl %esi, 12(%ebx)
|
||||
movl %edi, 16(%ebx)
|
||||
movl %ebp, 20(%ebx)
|
||||
1:`
|
||||
constraints = "={eax},{ebx},~{ebx},~{ecx},~{edx},~{esi},~{edi},~{ebp},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
|
||||
constraints = "={eax},{ebx},~{ecx},~{edx},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
|
||||
// This doesn't include the floating point stack because TinyGo uses
|
||||
// newer floating point instructions.
|
||||
case "x86_64":
|
||||
@@ -234,41 +244,119 @@ func (b *builder) createInvokeCheckpoint() {
|
||||
continueBB := b.insertBasicBlock("")
|
||||
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
||||
b.SetInsertPointAtEnd(continueBB)
|
||||
b.blockExits[b.currentBlock] = continueBB
|
||||
b.currentBlockInfo.exit = continueBB
|
||||
}
|
||||
|
||||
// isInLoop checks if there is a path from a basic block to itself.
|
||||
func isInLoop(start *ssa.BasicBlock) bool {
|
||||
// Use a breadth-first search to scan backwards through the block graph.
|
||||
queue := []*ssa.BasicBlock{start}
|
||||
checked := map[*ssa.BasicBlock]struct{}{}
|
||||
// createFaultCheckpoint is like createInvokeCheckpoint but for use in fault
|
||||
// blocks (e.g., bounds check failures). Unlike createInvokeCheckpoint, it does
|
||||
// not update currentBlockInfo.exit because the fault block is a dead-end that
|
||||
// does not participate in phi node resolution.
|
||||
func (b *builder) createFaultCheckpoint() {
|
||||
isZero := b.createCheckpoint(b.deferFrame)
|
||||
continueBB := b.insertBasicBlock("")
|
||||
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
||||
b.SetInsertPointAtEnd(continueBB)
|
||||
}
|
||||
|
||||
for len(queue) > 0 {
|
||||
// pop a block off of the queue
|
||||
block := queue[len(queue)-1]
|
||||
queue = queue[:len(queue)-1]
|
||||
// isInLoop checks if there is a path from the current block to itself.
|
||||
// Use Tarjan's strongly connected components algorithm to search for cycles.
|
||||
// A one-node SCC is a cycle iff there is an edge from the node to itself.
|
||||
// A multi-node SCC is always a cycle.
|
||||
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
func (b *builder) isInLoop() bool {
|
||||
if b.currentBlockInfo.tarjan.lowLink == 0 {
|
||||
b.strongConnect(b.currentBlock)
|
||||
}
|
||||
return b.currentBlockInfo.tarjan.cyclic
|
||||
}
|
||||
|
||||
// Search through predecessors.
|
||||
// Searching backwards means that this is pretty fast when the block is close to the start of the function.
|
||||
// Defers are often placed near the start of the function.
|
||||
for _, pred := range block.Preds {
|
||||
if pred == start {
|
||||
// cycle found
|
||||
return true
|
||||
}
|
||||
func (b *builder) strongConnect(block *ssa.BasicBlock) {
|
||||
// Assign a new index.
|
||||
// Indices start from 1 so that 0 can be used as a sentinel.
|
||||
assignedIndex := b.tarjanIndex + 1
|
||||
b.tarjanIndex = assignedIndex
|
||||
|
||||
if _, ok := checked[pred]; ok {
|
||||
// block already checked
|
||||
continue
|
||||
}
|
||||
// Apply the new index.
|
||||
blockIndex := block.Index
|
||||
node := &b.blockInfo[blockIndex].tarjan
|
||||
node.lowLink = assignedIndex
|
||||
|
||||
// add to queue and checked map
|
||||
queue = append(queue, pred)
|
||||
checked[pred] = struct{}{}
|
||||
// Push the node onto the stack.
|
||||
node.onStack = true
|
||||
b.tarjanStack = append(b.tarjanStack, uint(blockIndex))
|
||||
|
||||
// Process the successors.
|
||||
for _, successor := range block.Succs {
|
||||
// Look up the successor's state.
|
||||
successorIndex := successor.Index
|
||||
if successorIndex == blockIndex {
|
||||
// Handle a self-cycle specially.
|
||||
node.cyclic = true
|
||||
continue
|
||||
}
|
||||
successorNode := &b.blockInfo[successorIndex].tarjan
|
||||
|
||||
switch {
|
||||
case successorNode.lowLink == 0:
|
||||
// This node has not yet been visisted.
|
||||
b.strongConnect(successor)
|
||||
|
||||
case !successorNode.onStack:
|
||||
// This node has been visited, but is in a different SCC.
|
||||
// Ignore it, and do not update lowLink.
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the lowLink index.
|
||||
// This always uses the min-of-lowlink instead of using index in the on-stack case.
|
||||
// This is done for two reasons:
|
||||
// 1. The lowLink update can be shared between the new-node and on-stack cases.
|
||||
// 2. The assigned index does not need to be saved - it is only needed for root node detection.
|
||||
if successorNode.lowLink < node.lowLink {
|
||||
node.lowLink = successorNode.lowLink
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
if node.lowLink == assignedIndex {
|
||||
// This is a root node.
|
||||
// Pop the SCC off the stack.
|
||||
stack := b.tarjanStack
|
||||
top := stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
blocks := b.blockInfo
|
||||
topNode := &blocks[top].tarjan
|
||||
topNode.onStack = false
|
||||
|
||||
if top != uint(blockIndex) {
|
||||
// The root node is not the only node in the SCC.
|
||||
// Mark all nodes in this SCC as cyclic.
|
||||
topNode.cyclic = true
|
||||
for top != uint(blockIndex) {
|
||||
top = stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
topNode = &blocks[top].tarjan
|
||||
topNode.onStack = false
|
||||
topNode.cyclic = true
|
||||
}
|
||||
}
|
||||
|
||||
b.tarjanStack = stack
|
||||
}
|
||||
}
|
||||
|
||||
// tarjanNode holds per-block state for isInLoop and strongConnect.
|
||||
type tarjanNode struct {
|
||||
// lowLink is the index of the first visited node that is reachable from this block.
|
||||
// The lowLink indices are assigned by the SCC search, and do not correspond to b.Index.
|
||||
// A lowLink of 0 is used as a sentinel to mark a node which has not yet been visited.
|
||||
lowLink uint
|
||||
|
||||
// onStack tracks whether this node is currently on the SCC search stack.
|
||||
onStack bool
|
||||
|
||||
// cyclic indicates whether this block is in a loop.
|
||||
// If lowLink is 0, strongConnect must be called before reading this field.
|
||||
cyclic bool
|
||||
}
|
||||
|
||||
// createDefer emits a single defer instruction, to be run when this function
|
||||
@@ -410,7 +498,10 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
|
||||
// Put this struct in an allocation.
|
||||
var alloca llvm.Value
|
||||
if !isInLoop(instr.Block()) {
|
||||
if instr.Block() != b.currentBlock {
|
||||
panic("block mismatch")
|
||||
}
|
||||
if !b.isInLoop() {
|
||||
// This can safely use a stack allocation.
|
||||
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
|
||||
} else {
|
||||
@@ -418,7 +509,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
size := b.targetData.TypeAllocSize(deferredCallType)
|
||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||
nilPtr := llvm.ConstNull(b.dataPtrType)
|
||||
alloca = b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
|
||||
alloca = b.createAlloc(sizeValue, nilPtr, 0, "defer.alloc.call")
|
||||
}
|
||||
if b.NeedsStackObjects {
|
||||
b.trackPointer(alloca)
|
||||
@@ -582,8 +673,8 @@ func (b *builder) createRunDefers() {
|
||||
fn := callback.Fn.(*ssa.Function)
|
||||
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
|
||||
params := fn.Signature.Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||
for v := range params.Variables() {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(v.Type()))
|
||||
}
|
||||
valueTypes = append(valueTypes, b.dataPtrType) // closure
|
||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||
@@ -608,8 +699,8 @@ func (b *builder) createRunDefers() {
|
||||
|
||||
//Get signature from call results
|
||||
params := callback.Type().Underlying().(*types.Signature).Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||
for v := range params.Variables() {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(v.Type()))
|
||||
}
|
||||
|
||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||
|
||||
+2
-2
@@ -81,8 +81,8 @@ func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type {
|
||||
paramTypes = append(paramTypes, info.llvmType)
|
||||
}
|
||||
}
|
||||
for i := 0; i < typ.Params().Len(); i++ {
|
||||
subType := c.getLLVMType(typ.Params().At(i).Type())
|
||||
for v := range typ.Params().Variables() {
|
||||
subType := c.getLLVMType(v.Type())
|
||||
for _, info := range c.expandFormalParamType(subType, "", nil) {
|
||||
paramTypes = append(paramTypes, info.llvmType)
|
||||
}
|
||||
|
||||
+33
-8
@@ -5,11 +5,38 @@ package compiler
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"slices"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// Heap-allocate a buffer of the given size. This will typically call
|
||||
// runtime.alloc.
|
||||
func (b *builder) createAlloc(sizeValue, layoutValue llvm.Value, align int, comment string) llvm.Value {
|
||||
// Normally allocate using "runtime.alloc", but use "runtime.alloc_noheap"
|
||||
// if the //go:noheap pragma is used.
|
||||
allocFunc := "alloc"
|
||||
if b.info.noheap {
|
||||
allocFunc = "alloc_noheap"
|
||||
}
|
||||
|
||||
// Allocs that don't allocate anything can return an architecture-specific
|
||||
// sentinel value.
|
||||
if !sizeValue.IsAConstantInt().IsNil() && sizeValue.ZExtValue() == 0 {
|
||||
allocFunc = "alloc_zero"
|
||||
}
|
||||
|
||||
// Make the runtime call.
|
||||
call := b.createRuntimeCall(allocFunc, []llvm.Value{sizeValue, layoutValue}, comment)
|
||||
if align != 0 {
|
||||
// TODO: make sure all callsites set the correct alignment.
|
||||
call.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
// trackExpr inserts pointer tracking intrinsics for the GC if the expression is
|
||||
// one of the expressions that need this.
|
||||
func (b *builder) trackExpr(expr ssa.Value, value llvm.Value) {
|
||||
@@ -62,7 +89,7 @@ func (b *builder) trackValue(value llvm.Value) {
|
||||
return
|
||||
}
|
||||
numElements := typ.StructElementTypesCount()
|
||||
for i := 0; i < numElements; i++ {
|
||||
for i := range numElements {
|
||||
subValue := b.CreateExtractValue(value, i, "")
|
||||
b.trackValue(subValue)
|
||||
}
|
||||
@@ -71,7 +98,7 @@ func (b *builder) trackValue(value llvm.Value) {
|
||||
return
|
||||
}
|
||||
numElements := typ.ArrayLength()
|
||||
for i := 0; i < numElements; i++ {
|
||||
for i := range numElements {
|
||||
subValue := b.CreateExtractValue(value, i, "")
|
||||
b.trackValue(subValue)
|
||||
}
|
||||
@@ -92,13 +119,11 @@ func typeHasPointers(t llvm.Type) bool {
|
||||
case llvm.PointerTypeKind:
|
||||
return true
|
||||
case llvm.StructTypeKind:
|
||||
for _, subType := range t.StructElementTypes() {
|
||||
if typeHasPointers(subType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.ContainsFunc(t.StructElementTypes(), typeHasPointers)
|
||||
case llvm.ArrayTypeKind:
|
||||
if t.ArrayLength() == 0 {
|
||||
return false
|
||||
}
|
||||
if typeHasPointers(t.ElementType()) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
funcType = b.getLLVMFunctionType(instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||
params = append(params, context, funcPtr)
|
||||
hasContext = true
|
||||
prefix = b.fn.RelString(nil)
|
||||
prefix = b.getFunctionInfo(b.fn).linkName
|
||||
}
|
||||
|
||||
paramBundle := b.emitPointerPack(params)
|
||||
@@ -139,7 +139,7 @@ func (b *builder) createWasmExport() {
|
||||
// Declare the exported function.
|
||||
paramTypes := b.llvmFnType.ParamTypes()
|
||||
exportedFnType := llvm.FunctionType(b.llvmFnType.ReturnType(), paramTypes[:len(paramTypes)-1], false)
|
||||
exportedFn := llvm.AddFunction(b.mod, b.fn.RelString(nil)+suffix, exportedFnType)
|
||||
exportedFn := llvm.AddFunction(b.mod, b.getFunctionInfo(b.fn).linkName+suffix, exportedFnType)
|
||||
b.addStandardAttributes(exportedFn)
|
||||
llvmutil.AppendToGlobal(b.mod, "llvm.used", exportedFn)
|
||||
exportedFn.AddFunctionAttr(b.ctx.CreateStringAttribute("wasm-export-name", b.info.wasmExport))
|
||||
@@ -414,7 +414,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
||||
// Extract parameters from the state object, and call the function
|
||||
// that's being wrapped.
|
||||
var callParams []llvm.Value
|
||||
for i := 0; i < numParams; i++ {
|
||||
for i := range numParams {
|
||||
gep := b.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
|
||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
|
||||
|
||||
+12
-10
@@ -146,13 +146,14 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error
|
||||
llvmArgs := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
asm := "svc #" + strconv.FormatUint(num, 10)
|
||||
constraints := "={r0}"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={r0}")
|
||||
for i, arg := range args[1:] {
|
||||
arg = arg.(*ssa.MakeInterface).X
|
||||
if i == 0 {
|
||||
constraints += ",0"
|
||||
constraints.WriteString(",0")
|
||||
} else {
|
||||
constraints += ",{r" + strconv.Itoa(i) + "}"
|
||||
constraints.WriteString(",{r" + strconv.Itoa(i) + "}")
|
||||
}
|
||||
llvmValue := b.getValue(arg, pos)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
@@ -161,9 +162,9 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error
|
||||
// Implement the ARM calling convention by marking r1-r3 as
|
||||
// clobbered. r0 is used as an output register so doesn't have to be
|
||||
// marked as clobbered.
|
||||
constraints += ",~{r1},~{r2},~{r3}"
|
||||
constraints.WriteString(",~{r1},~{r2},~{r3}")
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints.String(), true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, llvmArgs, ""), nil
|
||||
}
|
||||
|
||||
@@ -184,13 +185,14 @@ func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, err
|
||||
llvmArgs := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
asm := "svc #" + strconv.FormatUint(num, 10)
|
||||
constraints := "={x0}"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={x0}")
|
||||
for i, arg := range args[1:] {
|
||||
arg = arg.(*ssa.MakeInterface).X
|
||||
if i == 0 {
|
||||
constraints += ",0"
|
||||
constraints.WriteString(",0")
|
||||
} else {
|
||||
constraints += ",{x" + strconv.Itoa(i) + "}"
|
||||
constraints.WriteString(",{x" + strconv.Itoa(i) + "}")
|
||||
}
|
||||
llvmValue := b.getValue(arg, pos)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
@@ -199,9 +201,9 @@ func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, err
|
||||
// Implement the ARM64 calling convention by marking x1-x7 as
|
||||
// clobbered. x0 is used as an output register so doesn't have to be
|
||||
// marked as clobbered.
|
||||
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
|
||||
constraints.WriteString(",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}")
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints.String(), true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, llvmArgs, ""), nil
|
||||
}
|
||||
|
||||
|
||||
+503
-105
@@ -10,6 +10,8 @@ import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -17,6 +19,12 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// numMethodHasMethodSet is a flag in bit 15 of the numMethod field (uint16) in
|
||||
// Named, Pointer, and Struct type descriptors. When set, an inline method set
|
||||
// is present in the type descriptor. Must match the constant in
|
||||
// src/internal/reflectlite/type.go.
|
||||
const numMethodHasMethodSet = 0x8000
|
||||
|
||||
// Type kinds for basic types.
|
||||
// They must match the constants for the Kind type in src/reflect/type.go.
|
||||
var basicTypes = [...]uint8{
|
||||
@@ -137,8 +145,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
// For a non-interface type, it returns the number of exported methods.
|
||||
// For an interface type, it returns the number of exported and unexported methods.
|
||||
var numMethods int
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
if isInterface || ms.At(i).Obj().Exported() {
|
||||
for method := range ms.Methods() {
|
||||
if isInterface || method.Obj().Exported() {
|
||||
numMethods++
|
||||
}
|
||||
}
|
||||
@@ -158,7 +166,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}
|
||||
}
|
||||
|
||||
typeCodeName, isLocal := getTypeCodeName(typ)
|
||||
typeCodeName, isLocal := c.getTypeCodeName(typ)
|
||||
globalName := "reflect/types.type:" + typeCodeName
|
||||
var global llvm.Value
|
||||
if isLocal {
|
||||
@@ -183,6 +191,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
typeFieldTypes := []*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
|
||||
}
|
||||
// Compute the method set value for types that support methods.
|
||||
var methods []*types.Func
|
||||
for method := range ms.Methods() {
|
||||
methods = append(methods, method.Obj().(*types.Func))
|
||||
}
|
||||
methodSetType := types.NewStruct([]*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
|
||||
types.NewVar(token.NoPos, nil, "methods", types.NewArray(types.Typ[types.UnsafePointer], int64(len(methods)))),
|
||||
}, nil)
|
||||
methodSetValue := c.getMethodSetValue(methods)
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
@@ -199,6 +217,13 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
|
||||
)
|
||||
case *types.Chan:
|
||||
@@ -218,6 +243,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
case *types.Array:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
@@ -242,11 +272,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
case *types.Interface:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
// TODO: methods
|
||||
case *types.Signature:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
@@ -292,14 +327,24 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
pkgname = pkg.Name()
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
namedNumMethods := uint64(numMethods)
|
||||
if namedNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on named type " + name)
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
if len(methods) > 0 {
|
||||
namedNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), namedNumMethods, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue) // methods
|
||||
}
|
||||
typeFields = append(typeFields, c.ctx.ConstString(pkgname+"."+name+"\x00", false)) // name
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
case *types.Chan:
|
||||
var dir reflectChanDir
|
||||
switch typ.Dir() {
|
||||
@@ -323,10 +368,20 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
}
|
||||
case *types.Pointer:
|
||||
ptrNumMethods := uint64(numMethods)
|
||||
if ptrNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on pointer type")
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
ptrNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
llvm.ConstInt(c.ctx.Int16Type(), ptrNumMethods, false), // numMethods
|
||||
c.getTypeCode(typ.Elem()),
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue)
|
||||
}
|
||||
case *types.Array:
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
|
||||
@@ -353,9 +408,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
|
||||
llvmStructType := c.getLLVMType(typ)
|
||||
size := c.targetData.TypeStoreSize(llvmStructType)
|
||||
structNumMethods := uint64(numMethods)
|
||||
if structNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on struct type")
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
structNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
llvm.ConstInt(c.ctx.Int16Type(), structNumMethods, 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
|
||||
@@ -407,9 +469,14 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}))
|
||||
}
|
||||
typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue)
|
||||
}
|
||||
case *types.Interface:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: methods
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)),
|
||||
methodSetValue,
|
||||
}
|
||||
case *types.Signature:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: params, return values, etc
|
||||
@@ -423,10 +490,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
c.getTypeMethodSet(typ),
|
||||
}, typeFields...)
|
||||
}
|
||||
alignment := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||
if alignment < 4 {
|
||||
alignment = 4
|
||||
}
|
||||
alignment := max(c.targetData.TypeAllocSize(c.dataPtrType), 4)
|
||||
globalValue := c.ctx.ConstStruct(typeFields, false)
|
||||
global.SetInitializer(globalValue)
|
||||
if isLocal {
|
||||
@@ -514,20 +578,50 @@ 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, bool) {
|
||||
//
|
||||
// isLocal is true when the type is declared inside a function body.
|
||||
// Such types need a per-declaration (or per instantiation) suffix
|
||||
// because their printed names are not unique.
|
||||
//
|
||||
// Ordinary function-local types (TypeName.Parent() != nil) are
|
||||
// disambiguated lazily from their declaration position: every
|
||||
// declaration in the package has a distinct (file, line, column)
|
||||
// triple, and the position is taken un-//line-adjusted so it is
|
||||
// stable across builds. Such types are only nameable inside their
|
||||
// declaring package, so the name does not need to agree with anything
|
||||
// computed in another package.
|
||||
//
|
||||
// Synthetic locals (TypeName.Parent() == nil), produced by generic
|
||||
// instantiation, are pre-registered by scanLocalTypes because their
|
||||
// names must agree across packages that materialize the same instance.
|
||||
func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bool) {
|
||||
switch t := types.Unalias(t).(type) {
|
||||
case *types.Named:
|
||||
if t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
||||
return "named:" + t.String() + "$local", true
|
||||
tn := t.Obj()
|
||||
if tn.Pkg() == nil || tn.Parent() == tn.Pkg().Scope() {
|
||||
// Package-scope or builtin: the printed name is unique.
|
||||
return "named:" + t.String(), false
|
||||
}
|
||||
return "named:" + t.String(), false
|
||||
if tn.Parent() != nil {
|
||||
// Ordinary function-local type. Use the un-//line-adjusted
|
||||
// declaration position as the disambiguator.
|
||||
pos := c.program.Fset.PositionFor(tn.Pos(), false)
|
||||
return fmt.Sprintf("named:%s$%s:%d:%d", t.String(), filepath.Base(pos.Filename), pos.Line, pos.Column), true
|
||||
}
|
||||
// Synthetic local from generic instantiation: must have been
|
||||
// pre-registered by scanLocalTypes.
|
||||
v := c.localTypeNames.At(t)
|
||||
if v == nil {
|
||||
panic("compiler: synthetic local type " + tn.Name() + " was not registered by scanLocalTypes")
|
||||
}
|
||||
return "named:" + v.(string), true
|
||||
case *types.Array:
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
s, isLocal := c.getTypeCodeName(t.Elem())
|
||||
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + s, isLocal
|
||||
case *types.Basic:
|
||||
return "basic:" + basicTypeNames[t.Kind()], false
|
||||
case *types.Chan:
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
s, isLocal := c.getTypeCodeName(t.Elem())
|
||||
var dir string
|
||||
switch t.Dir() {
|
||||
case types.SendOnly:
|
||||
@@ -547,7 +641,7 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
if !token.IsExported(name) {
|
||||
name = t.Method(i).Pkg().Path() + "." + name
|
||||
}
|
||||
s, local := getTypeCodeName(t.Method(i).Type())
|
||||
s, local := c.getTypeCodeName(t.Method(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
@@ -555,17 +649,17 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
}
|
||||
return "interface:" + "{" + strings.Join(methods, ",") + "}", isLocal
|
||||
case *types.Map:
|
||||
keyType, keyLocal := getTypeCodeName(t.Key())
|
||||
elemType, elemLocal := getTypeCodeName(t.Elem())
|
||||
keyType, keyLocal := c.getTypeCodeName(t.Key())
|
||||
elemType, elemLocal := c.getTypeCodeName(t.Elem())
|
||||
return "map:" + "{" + keyType + "," + elemType + "}", keyLocal || elemLocal
|
||||
case *types.Pointer:
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
s, isLocal := c.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++ {
|
||||
s, local := getTypeCodeName(t.Params().At(i).Type())
|
||||
s, local := c.getTypeCodeName(t.Params().At(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
@@ -573,7 +667,7 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
}
|
||||
results := make([]string, t.Results().Len())
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
s, local := getTypeCodeName(t.Results().At(i).Type())
|
||||
s, local := c.getTypeCodeName(t.Results().At(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
@@ -581,7 +675,7 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
}
|
||||
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}", isLocal
|
||||
case *types.Slice:
|
||||
s, isLocal := getTypeCodeName(t.Elem())
|
||||
s, isLocal := c.getTypeCodeName(t.Elem())
|
||||
return "slice:" + s, isLocal
|
||||
case *types.Struct:
|
||||
elems := make([]string, t.NumFields())
|
||||
@@ -591,7 +685,7 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
if t.Field(i).Embedded() {
|
||||
embedded = "#"
|
||||
}
|
||||
s, local := getTypeCodeName(t.Field(i).Type())
|
||||
s, local := c.getTypeCodeName(t.Field(i).Type())
|
||||
if local {
|
||||
isLocal = true
|
||||
}
|
||||
@@ -606,6 +700,232 @@ func getTypeCodeName(t types.Type) (string, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// scanLocalTypes assigns names to every synthetic *types.TypeName
|
||||
// (TypeName.Parent() == nil) reachable from this package and stores
|
||||
// them in c.localTypeNames.
|
||||
//
|
||||
// Synthetic TypeNames are produced by generic instantiation: two
|
||||
// instantiations of the same generic function (e.g. F[int] and
|
||||
// F[string]) produce TypeNames with the same printed name and the
|
||||
// same source position, so each is named with the enclosing
|
||||
// instance's RelString as prefix. RelString encodes the type
|
||||
// arguments, matching Go's runtime behavior, where F[int].Inner and
|
||||
// F[string].Inner are distinct types even when Inner does not mention
|
||||
// the type parameter.
|
||||
//
|
||||
// A given instance may be materialized by several packages (the body
|
||||
// of F[int] is compiled in every package that calls F[int]); its
|
||||
// reflect/types.type:* global has LinkOnceODRLinkage and is merged by
|
||||
// name at link time. The chosen name therefore depends only on
|
||||
// intrinsic SSA properties (RelString and the raw token.Pos used as a
|
||||
// sort key), so any package compiling the same instance produces the
|
||||
// same identifier.
|
||||
//
|
||||
// Ordinary function-local TypeNames (TypeName.Parent() != nil) are
|
||||
// not handled here: they are nameable only inside their declaring
|
||||
// package, and getTypeCodeName derives a stable per-declaration name
|
||||
// for them directly from their source position.
|
||||
func (c *compilerContext) scanLocalTypes(ssaPkg *ssa.Package) {
|
||||
// Locate every generic instance reachable from this package
|
||||
// (including instances declared in imported packages and any
|
||||
// function reached through an instance subtree).
|
||||
var instances []*ssa.Function
|
||||
seen := map[*ssa.Function]struct{}{}
|
||||
var walk func(fn *ssa.Function, inInstance bool)
|
||||
walk = func(fn *ssa.Function, inInstance bool) {
|
||||
if fn == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := seen[fn]; ok {
|
||||
return
|
||||
}
|
||||
// fn belongs to an instance subtree if it is itself an
|
||||
// instantiation or if we reached it from one.
|
||||
//
|
||||
// len(TypeArgs()) is used instead of fn.Origin() because
|
||||
// Origin() may call Build() on fn's declaring package, which
|
||||
// would defeat per-package compilation.
|
||||
isInstanceRoot := len(fn.TypeArgs()) > 0
|
||||
if !isInstanceRoot && !inInstance && fn.Pkg != ssaPkg {
|
||||
return
|
||||
}
|
||||
if fn.Blocks == nil && fn.AnonFuncs == nil {
|
||||
return
|
||||
}
|
||||
seen[fn] = struct{}{}
|
||||
isInInstance := inInstance || isInstanceRoot
|
||||
if isInInstance {
|
||||
instances = append(instances, fn)
|
||||
}
|
||||
for _, anon := range fn.AnonFuncs {
|
||||
walk(anon, isInInstance)
|
||||
}
|
||||
var ops [10]*ssa.Value
|
||||
for _, b := range fn.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
for _, op := range instr.Operands(ops[:0]) {
|
||||
if op == nil || *op == nil {
|
||||
continue
|
||||
}
|
||||
if callee, ok := (*op).(*ssa.Function); ok {
|
||||
walk(callee, isInInstance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, member := range ssaPkg.Members {
|
||||
switch m := member.(type) {
|
||||
case *ssa.Function:
|
||||
walk(m, false)
|
||||
case *ssa.Type:
|
||||
mset := c.program.MethodSets.MethodSet(m.Type())
|
||||
for method := range mset.Methods() {
|
||||
walk(c.program.MethodValue(method), false)
|
||||
}
|
||||
pmset := c.program.MethodSets.MethodSet(types.NewPointer(m.Type()))
|
||||
for method := range pmset.Methods() {
|
||||
walk(c.program.MethodValue(method), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Registration is first-writer-wins (a synthetic TypeName may be
|
||||
// reachable from several instances), so visit instances in a
|
||||
// deterministic order. Pos() is a defensive tiebreaker.
|
||||
sort.Slice(instances, func(i, j int) bool {
|
||||
ri, rj := instances[i].RelString(nil), instances[j].RelString(nil)
|
||||
if ri != rj {
|
||||
return ri < rj
|
||||
}
|
||||
return instances[i].Pos() < instances[j].Pos()
|
||||
})
|
||||
for _, fn := range instances {
|
||||
c.registerSyntheticLocalTypes(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// registerSyntheticLocalTypes walks every type reachable from fn's
|
||||
// body and records each synthetic *types.Named (TypeName.Parent() ==
|
||||
// nil) in c.localTypeNames. Each is named with fn.RelString as the
|
||||
// owning function plus a per-function counter assigned in source
|
||||
// order.
|
||||
//
|
||||
// First-writer-wins: a *types.Named already present in
|
||||
// c.localTypeNames is left alone, so a synthetic type reachable from
|
||||
// several instances keeps the name assigned by the first (in
|
||||
// scanLocalTypes' deterministic order).
|
||||
func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) {
|
||||
var found []*types.Named
|
||||
seen := map[types.Type]struct{}{}
|
||||
var visit func(t types.Type)
|
||||
visit = func(t types.Type) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := seen[t]; ok {
|
||||
return
|
||||
}
|
||||
seen[t] = struct{}{}
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
visit(types.Unalias(t))
|
||||
case *types.Named:
|
||||
tn := t.Obj()
|
||||
if tn.Pkg() != nil && tn.Parent() == nil {
|
||||
if c.localTypeNames.At(t) == nil {
|
||||
// Reserve the slot so later calls within this
|
||||
// scanLocalTypes invocation skip it; the final
|
||||
// name is filled in after sorting, before any
|
||||
// getTypeCodeName lookups happen.
|
||||
c.localTypeNames.Set(t, "")
|
||||
found = append(found, t)
|
||||
}
|
||||
}
|
||||
targs := t.TypeArgs()
|
||||
for t := range targs.Types() {
|
||||
visit(t)
|
||||
}
|
||||
visit(t.Underlying())
|
||||
case *types.Pointer:
|
||||
visit(t.Elem())
|
||||
case *types.Slice:
|
||||
visit(t.Elem())
|
||||
case *types.Array:
|
||||
visit(t.Elem())
|
||||
case *types.Chan:
|
||||
visit(t.Elem())
|
||||
case *types.Map:
|
||||
visit(t.Key())
|
||||
visit(t.Elem())
|
||||
case *types.Struct:
|
||||
for field := range t.Fields() {
|
||||
visit(field.Type())
|
||||
}
|
||||
case *types.Signature:
|
||||
if p := t.Params(); p != nil {
|
||||
for v := range p.Variables() {
|
||||
visit(v.Type())
|
||||
}
|
||||
}
|
||||
if r := t.Results(); r != nil {
|
||||
for v := range r.Variables() {
|
||||
visit(v.Type())
|
||||
}
|
||||
}
|
||||
case *types.Tuple:
|
||||
for v := range t.Variables() {
|
||||
visit(v.Type())
|
||||
}
|
||||
case *types.Interface:
|
||||
// A synthetic local type can be reachable only through a
|
||||
// local interface's method signature, so descend into
|
||||
// them. getTypeCodeName encodes those signatures into
|
||||
// the interface's identifier, and the seen map breaks
|
||||
// cycles formed by methods that mention the interface
|
||||
// itself.
|
||||
for method := range t.Methods() {
|
||||
visit(method.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, p := range fn.Params {
|
||||
visit(p.Type())
|
||||
}
|
||||
for _, fv := range fn.FreeVars {
|
||||
visit(fv.Type())
|
||||
}
|
||||
for _, l := range fn.Locals {
|
||||
visit(l.Type())
|
||||
}
|
||||
var ops [10]*ssa.Value
|
||||
for _, b := range fn.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
if v, ok := instr.(ssa.Value); ok {
|
||||
visit(v.Type())
|
||||
}
|
||||
for _, op := range instr.Operands(ops[:0]) {
|
||||
if op != nil && *op != nil {
|
||||
visit((*op).Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(found) == 0 {
|
||||
return
|
||||
}
|
||||
// Sort by raw token.Pos: this gives a total order on declarations
|
||||
// that is stable across builds and unaffected by //line directives
|
||||
// (which only adjust the human-facing position from Fset.Position).
|
||||
sort.Slice(found, func(i, j int) bool {
|
||||
return found[i].Obj().Pos() < found[j].Obj().Pos()
|
||||
})
|
||||
enclosing := fn.RelString(nil)
|
||||
for i, named := range found {
|
||||
c.localTypeNames.Set(named, fmt.Sprintf("%s.%s$%d", enclosing, named.Obj().Name(), i))
|
||||
}
|
||||
}
|
||||
|
||||
// getTypeMethodSet returns a reference (GEP) to a global method set. This
|
||||
// method set should be unreferenced after the interface lowering pass.
|
||||
func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
||||
@@ -616,8 +936,7 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
||||
|
||||
// Create method set.
|
||||
var signatures, wrappers []llvm.Value
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
method := ms.At(i)
|
||||
for method := range ms.Methods() {
|
||||
signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func))
|
||||
signatures = append(signatures, signatureGlobal)
|
||||
fn := c.program.MethodValue(method)
|
||||
@@ -696,20 +1015,14 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
// This type assertion always succeeds, so we can just set commaOk to true.
|
||||
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
|
||||
} else {
|
||||
// Type assert on interface type with methods.
|
||||
// This is a call to an interface type assert function.
|
||||
// The interface lowering pass will define this function by filling it
|
||||
// with a type switch over all concrete types that implement this
|
||||
// interface, and returning whether it's one of the matched types.
|
||||
// This is very different from how interface asserts are implemented in
|
||||
// the main Go compiler, where the runtime checks whether the type
|
||||
// implements each method of the interface. See:
|
||||
// https://research.swtch.com/interfaces
|
||||
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
|
||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||
// Type assert on an interface type with methods.
|
||||
// Create a call to a declared-but-not-defined function that will
|
||||
// be lowered by the interface lowering pass into a type-ID
|
||||
// comparison chain.
|
||||
commaOk = b.createInterfaceTypeAssert(intf, actualTypeNum)
|
||||
}
|
||||
} else {
|
||||
name, _ := getTypeCodeName(expr.AssertedType)
|
||||
name, _ := b.getTypeCodeName(expr.AssertedType)
|
||||
globalName := "reflect/types.typeid:" + name
|
||||
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
||||
if assertedTypeCodeGlobal.IsNil() {
|
||||
@@ -736,43 +1049,68 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
|
||||
prevBlock := b.GetInsertBlock()
|
||||
okBlock := b.insertBasicBlock("typeassert.ok")
|
||||
nextBlock := b.insertBasicBlock("typeassert.next")
|
||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||
|
||||
// Retrieve the value from the interface if the type assert was
|
||||
// successful.
|
||||
b.SetInsertPointAtEnd(okBlock)
|
||||
var valueOk llvm.Value
|
||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||
// Type assert on interface type. Easy: just return the same
|
||||
// interface value.
|
||||
valueOk = itf
|
||||
} else {
|
||||
// Type assert on concrete type. Extract the underlying type from
|
||||
// the interface (but only after checking it matches).
|
||||
valueOk = b.extractValueFromInterface(itf, assertedType)
|
||||
}
|
||||
b.CreateBr(nextBlock)
|
||||
|
||||
// Continue after the if statement.
|
||||
b.SetInsertPointAtEnd(nextBlock)
|
||||
phi := b.CreatePHI(assertedType, "typeassert.value")
|
||||
phi.AddIncoming([]llvm.Value{llvm.ConstNull(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
|
||||
|
||||
if expr.CommaOk {
|
||||
nextBlock := b.insertBasicBlock("typeassert.next")
|
||||
b.currentBlockInfo.exit = nextBlock
|
||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||
|
||||
// Retrieve the value from the interface if the type assert was
|
||||
// successful.
|
||||
b.SetInsertPointAtEnd(okBlock)
|
||||
var valueOk llvm.Value
|
||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||
// Type assert on interface type. Easy: just return the same
|
||||
// interface value.
|
||||
valueOk = itf
|
||||
} else {
|
||||
// Type assert on concrete type. Extract the underlying type from
|
||||
// the interface (but only after checking it matches).
|
||||
valueOk = b.extractValueFromInterface(itf, assertedType)
|
||||
}
|
||||
b.CreateBr(nextBlock)
|
||||
|
||||
// Continue after the if statement.
|
||||
b.SetInsertPointAtEnd(nextBlock)
|
||||
phi := b.CreatePHI(assertedType, "typeassert.value")
|
||||
phi.AddIncoming([]llvm.Value{llvm.ConstNull(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
|
||||
|
||||
tuple := b.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(b.ctx.Int1Type())}, false) // create empty tuple
|
||||
tuple = b.CreateInsertValue(tuple, phi, 0, "") // insert value
|
||||
tuple = b.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
|
||||
return tuple
|
||||
} else {
|
||||
// This is kind of dirty as the branch above becomes mostly useless,
|
||||
// but hopefully this gets optimized away.
|
||||
b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "")
|
||||
return phi
|
||||
// Type assert without comma-ok. If it fails, panic.
|
||||
faultBlock := b.getInterfaceAssertBlock()
|
||||
b.currentBlockInfo.exit = okBlock
|
||||
b.CreateCondBr(commaOk, okBlock, faultBlock)
|
||||
|
||||
// OK: extract the value from the interface.
|
||||
b.SetInsertPointAtEnd(okBlock)
|
||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||
return itf
|
||||
}
|
||||
return b.extractValueFromInterface(itf, assertedType)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) getInterfaceAssertBlock() llvm.BasicBlock {
|
||||
if !b.interfaceAssertBlock.IsNil() {
|
||||
return b.interfaceAssertBlock
|
||||
}
|
||||
savedBlock := b.GetInsertBlock()
|
||||
block := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.throw")
|
||||
b.interfaceAssertBlock = block
|
||||
b.SetInsertPointAtEnd(block)
|
||||
if b.hasDeferFrame() {
|
||||
b.createFaultCheckpoint()
|
||||
}
|
||||
b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
|
||||
b.CreateUnreachable()
|
||||
b.SetInsertPointAtEnd(savedBlock)
|
||||
return block
|
||||
}
|
||||
|
||||
// getMethodsString returns a string to be used in the "tinygo-methods" string
|
||||
// attribute for interface functions.
|
||||
func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
@@ -783,34 +1121,72 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
return strings.Join(methods, "; ")
|
||||
}
|
||||
|
||||
// getInterfaceImplementsFunc returns a declared function that works as a type
|
||||
// switch. The interface lowering pass will define this function.
|
||||
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
|
||||
s, _ := getTypeCodeName(assertedType.Underlying())
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
|
||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
// getMethodSetValue creates the method set struct value for a list of methods.
|
||||
// The struct contains a length and a sorted array of method signature pointers.
|
||||
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value {
|
||||
// Create a sorted list of method signature global names.
|
||||
type methodRef struct {
|
||||
name string
|
||||
value llvm.Value
|
||||
}
|
||||
return llvmFn
|
||||
var refs []methodRef
|
||||
for _, method := range methods {
|
||||
name := method.Name()
|
||||
if !token.IsExported(name) {
|
||||
name = method.Pkg().Path() + "." + name
|
||||
}
|
||||
s, _ := c.getTypeCodeName(method.Type())
|
||||
globalName := "reflect/types.signature:" + name + ":" + s
|
||||
value := c.mod.NamedGlobal(globalName)
|
||||
if value.IsNil() {
|
||||
value = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
|
||||
value.SetInitializer(llvm.ConstNull(c.ctx.Int8Type()))
|
||||
value.SetGlobalConstant(true)
|
||||
value.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
value.SetAlignment(1)
|
||||
if c.Debug {
|
||||
file := c.getDIFile("<Go type>")
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{
|
||||
Name: globalName,
|
||||
File: file,
|
||||
Line: 1,
|
||||
Type: c.getDIType(types.Typ[types.Uint8]),
|
||||
LocalToUnit: false,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
AlignInBits: 8,
|
||||
})
|
||||
value.AddMetadata(0, diglobal)
|
||||
}
|
||||
}
|
||||
refs = append(refs, methodRef{globalName, value})
|
||||
}
|
||||
sort.Slice(refs, func(i, j int) bool {
|
||||
return refs[i].name < refs[j].name
|
||||
})
|
||||
|
||||
var values []llvm.Value
|
||||
for _, ref := range refs {
|
||||
values = append(values, ref.value)
|
||||
}
|
||||
|
||||
return c.ctx.ConstStruct([]llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, uint64(len(values)), false),
|
||||
llvm.ConstArray(c.dataPtrType, values),
|
||||
}, false)
|
||||
}
|
||||
|
||||
// getInvokeFunction returns the thunk to call the given interface method. The
|
||||
// thunk is declared, not defined: it will be defined by the interface lowering
|
||||
// pass.
|
||||
func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
||||
s, _ := getTypeCodeName(instr.Value.Type().Underlying())
|
||||
s, _ := c.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)
|
||||
var paramTuple []*types.Var
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
paramTuple = append(paramTuple, sig.Params().At(i))
|
||||
for v := range sig.Params().Variables() {
|
||||
paramTuple = append(paramTuple, v)
|
||||
}
|
||||
paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer]))
|
||||
llvmFnType := c.getLLVMFunctionType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false))
|
||||
@@ -823,6 +1199,24 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
// createInterfaceTypeAssert creates a call to a declared-but-not-defined
|
||||
// $typeassert function for the given interface. This function will be defined
|
||||
// by the interface lowering pass as a type-ID comparison chain, avoiding the
|
||||
// need for runtime.typeImplementsMethodSet at compile time.
|
||||
func (b *builder) createInterfaceTypeAssert(intf *types.Interface, actualType llvm.Value) llvm.Value {
|
||||
s, _ := b.getTypeCodeName(intf)
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := b.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{b.dataPtrType}, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, fnName, llvmFnType)
|
||||
b.addStandardDeclaredAttributes(llvmFn)
|
||||
methods := b.getMethodsString(intf)
|
||||
llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
}
|
||||
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{actualType}, "")
|
||||
}
|
||||
|
||||
// getInterfaceInvokeWrapper returns a wrapper for the given method so it can be
|
||||
// invoked from an interface. The wrapper takes in a pointer to the underlying
|
||||
// value, dereferences or unpacks it if necessary, and calls the real method.
|
||||
@@ -909,34 +1303,38 @@ func methodSignature(method *types.Func) string {
|
||||
// () string
|
||||
// (string, int) (int, error)
|
||||
func signature(sig *types.Signature) string {
|
||||
s := ""
|
||||
var s strings.Builder
|
||||
if sig.Params().Len() == 0 {
|
||||
s += "()"
|
||||
s.WriteString("()")
|
||||
} else {
|
||||
s += "("
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
s.WriteString("(")
|
||||
i := 0
|
||||
for v := range sig.Params().Variables() {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s += typestring(sig.Params().At(i).Type())
|
||||
s.WriteString(typestring(v.Type()))
|
||||
i++
|
||||
}
|
||||
s += ")"
|
||||
s.WriteString(")")
|
||||
}
|
||||
if sig.Results().Len() == 0 {
|
||||
// keep as-is
|
||||
} else if sig.Results().Len() == 1 {
|
||||
s += " " + typestring(sig.Results().At(0).Type())
|
||||
s.WriteString(" " + typestring(sig.Results().At(0).Type()))
|
||||
} else {
|
||||
s += " ("
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
s.WriteString(" (")
|
||||
i := 0
|
||||
for v := range sig.Results().Variables() {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s += typestring(sig.Results().At(i).Type())
|
||||
s.WriteString(typestring(v.Type()))
|
||||
i++
|
||||
}
|
||||
s += ")"
|
||||
s.WriteString(")")
|
||||
}
|
||||
return s
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// typestring returns a stable (human-readable) type string for the given type
|
||||
|
||||
+88
-16
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -27,6 +28,8 @@ func (b *builder) defineIntrinsicFunction() {
|
||||
b.createStackSaveImpl()
|
||||
case name == "runtime.KeepAlive":
|
||||
b.createKeepAliveImpl()
|
||||
case name == "machine.keepAliveNoEscape":
|
||||
b.createMachineKeepAliveImpl()
|
||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||
b.createVolatileLoad()
|
||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||
@@ -48,19 +51,24 @@ func (b *builder) defineIntrinsicFunction() {
|
||||
// and will otherwise be lowered to regular libc memcpy/memmove calls.
|
||||
func (b *builder) createMemoryCopyImpl() {
|
||||
b.createFunctionStart(true)
|
||||
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||
params := b.fn.Params[0:3]
|
||||
b.createMemCopy(
|
||||
b.fn.Name(),
|
||||
b.getValue(params[0], getPos(b.fn)),
|
||||
b.getValue(params[1], getPos(b.fn)),
|
||||
b.getValue(params[2], getPos(b.fn)),
|
||||
)
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
func (b *builder) createMemCopy(kind string, dst, src, len llvm.Value) llvm.Value {
|
||||
fnName := "llvm." + kind + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||
llvmFn := b.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType, b.dataPtrType, b.uintptrType, b.ctx.Int1Type()}, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
||||
}
|
||||
var params []llvm.Value
|
||||
for _, param := range b.fn.Params {
|
||||
params = append(params, b.getValue(param, getPos(b.fn)))
|
||||
}
|
||||
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
|
||||
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
|
||||
b.CreateRetVoid()
|
||||
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{dst, src, len, llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
|
||||
}
|
||||
|
||||
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
|
||||
@@ -144,13 +152,37 @@ func (b *builder) createAbiEscapeImpl() {
|
||||
b.CreateRet(result)
|
||||
}
|
||||
|
||||
// Implement machine.keepAliveNoEscape, which makes sure the compiler keeps the
|
||||
// pointer parameter alive until this point (for GC).
|
||||
func (b *builder) createMachineKeepAliveImpl() {
|
||||
b.createFunctionStart(true)
|
||||
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
|
||||
// See createKeepAliveImpl for details.
|
||||
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
|
||||
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
|
||||
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
var mathToLLVMMapping = map[string]string{
|
||||
"math.Acos": "llvm.acos.f64",
|
||||
"math.Asin": "llvm.asin.f64",
|
||||
"math.Atan": "llvm.atan.f64",
|
||||
"math.Atan2": "llvm.atan2.f64",
|
||||
"math.Ceil": "llvm.ceil.f64",
|
||||
"math.Cos": "llvm.cos.f64",
|
||||
"math.Cosh": "llvm.cosh.f64",
|
||||
"math.Exp": "llvm.exp.f64",
|
||||
"math.Exp2": "llvm.exp2.f64",
|
||||
"math.Floor": "llvm.floor.f64",
|
||||
"math.Log": "llvm.log.f64",
|
||||
"math.Sin": "llvm.sin.f64",
|
||||
"math.Sinh": "llvm.sinh.f64",
|
||||
"math.Sqrt": "llvm.sqrt.f64",
|
||||
"math.Tan": "llvm.tan.f64",
|
||||
"math.Tanh": "llvm.tanh.f64",
|
||||
"math.Trunc": "llvm.trunc.f64",
|
||||
}
|
||||
|
||||
@@ -164,18 +196,40 @@ var mathToLLVMMapping = map[string]string{
|
||||
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
|
||||
// beneficial on architectures where 64-bit floating point operations are (much)
|
||||
// more expensive than 32-bit ones.
|
||||
func (b *builder) defineMathOp() {
|
||||
b.createFunctionStart(true)
|
||||
llvmName := mathToLLVMMapping[b.fn.RelString(nil)]
|
||||
if llvmName == "" {
|
||||
panic("unreachable: unknown math operation") // sanity check
|
||||
func (b *builder) defineMathOp() bool {
|
||||
llvmName, ok := mathToLLVMMapping[b.fn.RelString(nil)]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(b.Triple, "-wasi") || llvmutil.Version() < 19 {
|
||||
// We don't have a real libc for wasip2. Until that is fixed, we need to
|
||||
// limit math intrinsics on WASI to a subset supported natively in
|
||||
// WebAssembly.
|
||||
// Also, since we don't know the specific libc we will target, disallow
|
||||
// these for all WASI targets.
|
||||
//
|
||||
// We also need to limit ourselves to LLVM 19 and above for the extended
|
||||
// set of math intrinsics, see:
|
||||
// https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294
|
||||
switch b.fn.Name() {
|
||||
case "Ceil", "Exp", "Exp2", "Floor", "Log", "Sqrt", "Trunc":
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
b.createFunctionStart(true)
|
||||
llvmFn := b.mod.NamedFunction(llvmName)
|
||||
if llvmFn.IsNil() {
|
||||
// The intrinsic doesn't exist yet, so declare it.
|
||||
// At the moment, all supported intrinsics have the form "double
|
||||
// foo(double %x)" so we can hardcode the signature here.
|
||||
llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
|
||||
var llvmType llvm.Type
|
||||
switch b.fn.Name() {
|
||||
case "Atan2":
|
||||
// double atan2(double %y, double %x)
|
||||
llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false)
|
||||
default:
|
||||
// double foo(double %x)
|
||||
llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
|
||||
}
|
||||
llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType)
|
||||
}
|
||||
// Create a call to the intrinsic.
|
||||
@@ -185,6 +239,24 @@ func (b *builder) defineMathOp() {
|
||||
}
|
||||
result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *builder) defineCryptoIntrinsic() bool {
|
||||
if b.fn.Pkg.Pkg.Path() != "crypto/internal/constanttime" {
|
||||
return false
|
||||
}
|
||||
|
||||
switch b.fn.Name() {
|
||||
case "boolToUint8":
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
result := b.CreateZExt(param, b.ctx.Int8Type(), "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Implement most math/bits functions.
|
||||
|
||||
+93
-99
@@ -1,10 +1,10 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
@@ -129,13 +129,7 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
|
||||
// Packed data is bigger than a pointer, so allocate it on the heap.
|
||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||
align := b.targetData.ABITypeAlignment(packedType)
|
||||
alloc := b.mod.NamedFunction("runtime.alloc")
|
||||
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
|
||||
sizeValue,
|
||||
llvm.ConstNull(b.dataPtrType),
|
||||
llvm.Undef(b.dataPtrType), // unused context parameter
|
||||
}, "")
|
||||
packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
|
||||
packedAlloc := b.createAlloc(sizeValue, llvm.ConstNull(b.dataPtrType), align, "")
|
||||
if b.NeedsStackObjects {
|
||||
b.trackPointer(packedAlloc)
|
||||
}
|
||||
@@ -212,7 +206,7 @@ func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType l
|
||||
globalType := llvm.ArrayType(elementType, len(buf))
|
||||
global := llvm.AddGlobal(c.mod, globalType, name)
|
||||
value := llvm.Undef(globalType)
|
||||
for i := 0; i < len(buf); i++ {
|
||||
for i := range buf {
|
||||
ch := uint64(buf[i])
|
||||
value = c.builder.CreateInsertValue(value, llvm.ConstInt(elementType, ch, false), i, "")
|
||||
}
|
||||
@@ -231,6 +225,12 @@ func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType l
|
||||
//
|
||||
// For details on what's in this value, see src/runtime/gc_precise.go.
|
||||
func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Value {
|
||||
if !typeHasPointers(t) {
|
||||
// There are no pointers in this type, so we can simplify the layout.
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
|
||||
// Use the element type for arrays. This works even for nested arrays.
|
||||
for {
|
||||
kind := t.TypeKind()
|
||||
@@ -248,54 +248,29 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
break
|
||||
}
|
||||
|
||||
// Do a few checks to see whether we need to generate any object layout
|
||||
// information at all.
|
||||
// Create the pointer bitmap.
|
||||
objectSizeBytes := c.targetData.TypeAllocSize(t)
|
||||
pointerAlignment := uint64(c.targetData.PrefTypeAlignment(c.dataPtrType))
|
||||
bitmapLen := objectSizeBytes / pointerAlignment
|
||||
bitmapBytes := (bitmapLen + 7) / 8
|
||||
bitmap := make([]byte, bitmapBytes, max(bitmapBytes, 8))
|
||||
c.buildPointerBitmap(bitmap, pointerAlignment, pos, t, 0)
|
||||
|
||||
// Try to encode the layout inline.
|
||||
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||
if objectSizeBytes < pointerSize {
|
||||
// Too small to contain a pointer.
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
bitmap := c.getPointerBitmap(t, pos)
|
||||
if bitmap.BitLen() == 0 {
|
||||
// There are no pointers in this type, so we can simplify the layout.
|
||||
// TODO: this can be done in many other cases, e.g. when allocating an
|
||||
// array (like [4][]byte, which repeats a slice 4 times).
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
if objectSizeBytes%uint64(pointerAlignment) != 0 {
|
||||
// This shouldn't happen except for packed structs, which aren't
|
||||
// currently used.
|
||||
c.addError(pos, "internal error: unexpected object size for object with pointer field")
|
||||
return llvm.ConstNull(c.dataPtrType)
|
||||
}
|
||||
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
|
||||
|
||||
pointerBits := pointerSize * 8
|
||||
var sizeFieldBits uint64
|
||||
switch pointerBits {
|
||||
case 16:
|
||||
sizeFieldBits = 4
|
||||
case 32:
|
||||
sizeFieldBits = 5
|
||||
case 64:
|
||||
sizeFieldBits = 6
|
||||
default:
|
||||
panic("unknown pointer size")
|
||||
}
|
||||
layoutFieldBits := pointerBits - 1 - sizeFieldBits
|
||||
if bitmapLen < pointerBits {
|
||||
rawMask := binary.LittleEndian.Uint64(bitmap[0:8])
|
||||
layout := rawMask*pointerBits + bitmapLen
|
||||
layout <<= 1
|
||||
layout |= 1
|
||||
|
||||
// Try to emit the value as an inline integer. This is possible in most
|
||||
// cases.
|
||||
if objectSizeWords < layoutFieldBits {
|
||||
// If it can be stored directly in the pointer value, do so.
|
||||
// The runtime knows that if the least significant bit of the pointer is
|
||||
// set, the pointer contains the value itself.
|
||||
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
// Check if the layout fits.
|
||||
layout &= 1<<pointerBits - 1
|
||||
if (layout>>1)/pointerBits == rawMask {
|
||||
// No set bits were shifted off.
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately, the object layout is too big to fit in a pointer-sized
|
||||
@@ -303,25 +278,24 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
|
||||
// Try first whether the global already exists. All objects with a
|
||||
// particular name have the same type, so this is possible.
|
||||
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
|
||||
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", bitmapLen, (bitmapLen+15)/16, bitmap)
|
||||
global := c.mod.NamedGlobal(globalName)
|
||||
if !global.IsNil() {
|
||||
return global
|
||||
}
|
||||
|
||||
// Create the global initializer.
|
||||
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
|
||||
bitmap.FillBytes(bitmapBytes)
|
||||
reverseBytes(bitmapBytes) // big-endian to little-endian
|
||||
var bitmapByteValues []llvm.Value
|
||||
for _, b := range bitmapBytes {
|
||||
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
|
||||
bitmapByteValues := make([]llvm.Value, bitmapBytes)
|
||||
i8 := c.ctx.Int8Type()
|
||||
for i, b := range bitmap {
|
||||
bitmapByteValues[i] = llvm.ConstInt(i8, uint64(b), false)
|
||||
}
|
||||
initializer := c.ctx.ConstStruct([]llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, objectSizeWords, false),
|
||||
llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
|
||||
llvm.ConstInt(c.uintptrType, bitmapLen, false),
|
||||
llvm.ConstArray(i8, bitmapByteValues),
|
||||
}, false)
|
||||
|
||||
// Create the actual global.
|
||||
global = llvm.AddGlobal(c.mod, initializer.Type(), globalName)
|
||||
global.SetInitializer(initializer)
|
||||
global.SetUnnamedAddr(true)
|
||||
@@ -329,6 +303,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 {
|
||||
// AVR doesn't have alignment by default.
|
||||
// The lowest bit must be unset to distinguish this from an inline layout.
|
||||
global.SetAlignment(2)
|
||||
}
|
||||
if c.Debug && pos != token.NoPos {
|
||||
@@ -360,52 +335,71 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
return global
|
||||
}
|
||||
|
||||
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||
// bigint at the word offset that contains a pointer. This scan is recursive.
|
||||
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
|
||||
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||
switch typ.TypeKind() {
|
||||
// buildPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||
// bitmap at the word offset that contains a pointer. This scan is recursive.
|
||||
func (c *compilerContext) buildPointerBitmap(
|
||||
dst []byte,
|
||||
ptrAlign uint64,
|
||||
pos token.Pos,
|
||||
t llvm.Type,
|
||||
offset uint64,
|
||||
) {
|
||||
switch t.TypeKind() {
|
||||
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
||||
return big.NewInt(0)
|
||||
// These types do not contain pointers.
|
||||
|
||||
case llvm.PointerTypeKind:
|
||||
return big.NewInt(1)
|
||||
// Set the corresponding position in the bitmap.
|
||||
dst[offset/8] |= 1 << (offset % 8)
|
||||
|
||||
case llvm.StructTypeKind:
|
||||
ptrs := big.NewInt(0)
|
||||
for i, subtyp := range typ.StructElementTypes() {
|
||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
||||
if subptrs.BitLen() == 0 {
|
||||
// Recurse over struct elements.
|
||||
for i, et := range t.StructElementTypes() {
|
||||
eo := c.targetData.ElementOffset(t, i)
|
||||
if eo%uint64(ptrAlign) != 0 {
|
||||
if typeHasPointers(et) {
|
||||
// This error will let the compilation fail, but by continuing
|
||||
// the error can still easily be shown.
|
||||
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
||||
}
|
||||
continue
|
||||
}
|
||||
offset := c.targetData.ElementOffset(typ, i)
|
||||
if offset%uint64(alignment) != 0 {
|
||||
// This error will let the compilation fail, but by continuing
|
||||
// the error can still easily be shown.
|
||||
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
||||
continue
|
||||
}
|
||||
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
|
||||
ptrs.Or(ptrs, subptrs)
|
||||
c.buildPointerBitmap(
|
||||
dst,
|
||||
ptrAlign,
|
||||
pos,
|
||||
et,
|
||||
offset+(eo/ptrAlign),
|
||||
)
|
||||
}
|
||||
return ptrs
|
||||
|
||||
case llvm.ArrayTypeKind:
|
||||
subtyp := typ.ElementType()
|
||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
||||
ptrs := big.NewInt(0)
|
||||
if subptrs.BitLen() == 0 {
|
||||
return ptrs
|
||||
// Recurse over array elements.
|
||||
len := t.ArrayLength()
|
||||
if len <= 0 {
|
||||
return
|
||||
}
|
||||
elementSize := c.targetData.TypeAllocSize(subtyp)
|
||||
if elementSize%uint64(alignment) != 0 {
|
||||
// This error will let the compilation fail (but continues so that
|
||||
// other errors can be shown).
|
||||
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
||||
return ptrs
|
||||
et := t.ElementType()
|
||||
elementSize := c.targetData.TypeAllocSize(et)
|
||||
if elementSize%ptrAlign != 0 {
|
||||
if typeHasPointers(et) {
|
||||
// This error will let the compilation fail (but continues so that
|
||||
// other errors can be shown).
|
||||
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < typ.ArrayLength(); i++ {
|
||||
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
|
||||
ptrs.Or(ptrs, subptrs)
|
||||
elementSize /= ptrAlign
|
||||
for i := range len {
|
||||
c.buildPointerBitmap(
|
||||
dst,
|
||||
ptrAlign,
|
||||
pos,
|
||||
et,
|
||||
offset+uint64(i)*elementSize,
|
||||
)
|
||||
}
|
||||
return ptrs
|
||||
|
||||
default:
|
||||
// Should not happen.
|
||||
panic("unknown LLVM type")
|
||||
@@ -423,7 +417,7 @@ func (c *compilerContext) archFamily() string {
|
||||
// features string is not one for an ARM architecture.
|
||||
func (c *compilerContext) isThumb() bool {
|
||||
var isThumb, isNotThumb bool
|
||||
for _, feature := range strings.Split(c.Features, ",") {
|
||||
for feature := range strings.SplitSeq(c.Features, ",") {
|
||||
if feature == "+thumb-mode" {
|
||||
isThumb = true
|
||||
}
|
||||
|
||||
+457
-165
@@ -3,42 +3,29 @@ package compiler
|
||||
// This file emits the correct map intrinsics for map operations.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"github.com/tinygo-org/tinygo/src/tinygo"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"strings"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
const hashArrayUnrollLimit = 4
|
||||
|
||||
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
||||
// initializing an appropriately sized object.
|
||||
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
mapType := expr.Type().Underlying().(*types.Map)
|
||||
keyType := mapType.Key().Underlying()
|
||||
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
||||
var llvmKeyType llvm.Type
|
||||
var alg uint64
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// String keys.
|
||||
llvmKeyType = b.getLLVMType(keyType)
|
||||
alg = uint64(tinygo.HashmapAlgorithmString)
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// Trivially comparable keys.
|
||||
llvmKeyType = b.getLLVMType(keyType)
|
||||
alg = uint64(tinygo.HashmapAlgorithmBinary)
|
||||
} else {
|
||||
// All other keys. Implemented as map[interface{}]valueType for ease of
|
||||
// implementation.
|
||||
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
||||
alg = uint64(tinygo.HashmapAlgorithmInterface)
|
||||
}
|
||||
llvmKeyType := b.getLLVMType(keyType)
|
||||
|
||||
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
||||
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
||||
llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
|
||||
llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
|
||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
|
||||
if expr.Reserve != nil {
|
||||
sizeHint = b.getValue(expr.Reserve, getPos(expr))
|
||||
var err error
|
||||
@@ -47,10 +34,42 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
}
|
||||
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
|
||||
|
||||
// Resolve hash and equal functions for this key type. For string and
|
||||
// binary key types, reference the corresponding runtime functions
|
||||
// directly. For composite types, generate type-specific functions.
|
||||
var hashFn, equalFn llvm.Value
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
hashFn = b.getRuntimeFunctionValue("hashmapStringPtrHash", hashmapKeyHashSignature())
|
||||
equalFn = b.getRuntimeFunctionValue("hashmapStringEqual", hashmapKeyEqualSignature())
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
hashFn = b.getRuntimeFunctionValue("hash32", hashmapKeyHashSignature())
|
||||
equalFn = b.getRuntimeFunctionValue("memequal", hashmapKeyEqualSignature())
|
||||
} else {
|
||||
fn := b.getOrGenerateKeyHashFunc(keyType)
|
||||
hashFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyHashSignature())
|
||||
fn = b.getOrGenerateKeyEqualFunc(keyType)
|
||||
equalFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyEqualSignature())
|
||||
}
|
||||
|
||||
hashmap := b.createRuntimeCall("hashmapMakeGeneric", []llvm.Value{
|
||||
llvmKeySize, llvmValueSize, sizeHint,
|
||||
hashFn, equalFn,
|
||||
}, "")
|
||||
return hashmap, nil
|
||||
}
|
||||
|
||||
// getRuntimeFunctionValue returns a TinyGo function value (with nil context)
|
||||
// for the named runtime function.
|
||||
func (b *builder) getRuntimeFunctionValue(name string, sig *types.Signature) llvm.Value {
|
||||
member := b.program.ImportedPackage("runtime").Members[name]
|
||||
if member == nil {
|
||||
panic("unknown runtime function: " + name)
|
||||
}
|
||||
_, llvmFn := b.getFunction(member.(*ssa.Function))
|
||||
return b.createFuncValue(llvmFn, llvm.ConstNull(b.dataPtrType), sig)
|
||||
}
|
||||
|
||||
// createMapLookup returns the value in a map. It calls a runtime function
|
||||
// depending on the map key type to load the map value and its comma-ok value.
|
||||
func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
|
||||
@@ -72,32 +91,23 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
||||
|
||||
// Do the lookup. How it is done depends on the key type.
|
||||
var commaOkValue llvm.Value
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
params := []llvm.Value{m, key, mapValueAlloca, mapValueSize}
|
||||
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// key can be compared with runtime.memequal
|
||||
// Store the key in an alloca, in the entry block to avoid dynamic stack
|
||||
// growth.
|
||||
} else {
|
||||
// Key stored at actual type: either binary-comparable or with
|
||||
// compiler-generated hash/equal.
|
||||
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||
b.CreateStore(key, mapKeyAlloca)
|
||||
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
|
||||
// Fetch the value from the hashmap.
|
||||
params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize}
|
||||
commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
|
||||
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
|
||||
} else {
|
||||
// Not trivially comparable using memcmp. Make it an interface instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface now.
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
fnName := "hashmapBinaryGet"
|
||||
if !hashmapIsBinaryKey(keyType) {
|
||||
fnName = "hashmapGenericGet"
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, mapValueAlloca, mapValueSize}
|
||||
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
|
||||
commaOkValue = b.createRuntimeCall(fnName, params, "")
|
||||
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
|
||||
}
|
||||
|
||||
// Load the resulting value from the hashmap. The value is set to the zero
|
||||
@@ -120,29 +130,22 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
||||
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
||||
valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
|
||||
b.CreateStore(value, valueAlloca)
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
params := []llvm.Value{m, key, valueAlloca}
|
||||
b.createRuntimeCall("hashmapStringSet", params, "")
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// key can be compared with runtime.memequal
|
||||
b.createRuntimeInvoke("hashmapStringSet", params, "")
|
||||
} else {
|
||||
// Key stored at actual type.
|
||||
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||
b.CreateStore(key, keyAlloca)
|
||||
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
||||
params := []llvm.Value{m, keyAlloca, valueAlloca}
|
||||
b.createRuntimeCall("hashmapBinarySet", params, "")
|
||||
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||
} else {
|
||||
// Key is not trivially comparable, so compare it as an interface instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
fnName := "hashmapBinarySet"
|
||||
if !hashmapIsBinaryKey(keyType) {
|
||||
fnName = "hashmapGenericSet"
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, valueAlloca}
|
||||
b.createRuntimeCall("hashmapInterfaceSet", params, "")
|
||||
params := []llvm.Value{m, keyAlloca, valueAlloca}
|
||||
b.createRuntimeInvoke(fnName, params, "")
|
||||
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||
}
|
||||
b.emitLifetimeEnd(valueAlloca, valueSize)
|
||||
}
|
||||
@@ -150,31 +153,23 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
|
||||
// createMapDelete deletes a key from a map by calling the appropriate runtime
|
||||
// function. It is the implementation of the Go delete() builtin.
|
||||
func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
|
||||
origKeyType := keyType
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
params := []llvm.Value{m, key}
|
||||
b.createRuntimeCall("hashmapStringDelete", params, "")
|
||||
return nil
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
} else {
|
||||
// Key stored at actual type.
|
||||
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||
b.CreateStore(key, keyAlloca)
|
||||
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
||||
params := []llvm.Value{m, keyAlloca}
|
||||
b.createRuntimeCall("hashmapBinaryDelete", params, "")
|
||||
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||
return nil
|
||||
} else {
|
||||
// Key is not trivially comparable, so compare it as an interface
|
||||
// instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||
fnName := "hashmapBinaryDelete"
|
||||
if !hashmapIsBinaryKey(keyType) {
|
||||
fnName = "hashmapGenericDelete"
|
||||
}
|
||||
params := []llvm.Value{m, itfKey}
|
||||
b.createRuntimeCall("hashmapInterfaceDelete", params, "")
|
||||
params := []llvm.Value{m, keyAlloca}
|
||||
b.createRuntimeCall(fnName, params, "")
|
||||
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -195,42 +190,15 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
|
||||
llvmKeyType := b.getLLVMType(keyType)
|
||||
llvmValueType := b.getLLVMType(valueType)
|
||||
|
||||
// There is a special case in which keys are stored as an interface value
|
||||
// instead of the value they normally are. This happens for non-trivially
|
||||
// comparable types such as float32 or some structs.
|
||||
isKeyStoredAsInterface := false
|
||||
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// key can be compared with runtime.memequal
|
||||
} else {
|
||||
// The key is stored as an interface value, and may or may not be an
|
||||
// interface type (for example, float32 keys are stored as an interface
|
||||
// value).
|
||||
if _, ok := keyType.Underlying().(*types.Interface); !ok {
|
||||
isKeyStoredAsInterface = true
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the type of the key as stored in the map.
|
||||
llvmStoredKeyType := llvmKeyType
|
||||
if isKeyStoredAsInterface {
|
||||
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
|
||||
}
|
||||
// All key types are now stored at their declared type (no interface wrapping).
|
||||
|
||||
// Extract the key and value from the map.
|
||||
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
|
||||
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
|
||||
mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
||||
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next")
|
||||
mapKey := b.CreateLoad(llvmStoredKeyType, mapKeyAlloca, "")
|
||||
mapKey := b.CreateLoad(llvmKeyType, mapKeyAlloca, "")
|
||||
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
|
||||
|
||||
if isKeyStoredAsInterface {
|
||||
// The key is stored as an interface but it isn't of interface type.
|
||||
// Extract the underlying value.
|
||||
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
|
||||
}
|
||||
|
||||
// End the lifetimes of the allocas, because we're done with them.
|
||||
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
|
||||
b.emitLifetimeEnd(mapValueAlloca, mapValueSize)
|
||||
@@ -250,17 +218,9 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
|
||||
func hashmapIsBinaryKey(keyType types.Type) bool {
|
||||
switch keyType := keyType.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
|
||||
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 || keyType.Kind() == types.UnsafePointer
|
||||
case *types.Pointer:
|
||||
return true
|
||||
case *types.Struct:
|
||||
for i := 0; i < keyType.NumFields(); i++ {
|
||||
fieldType := keyType.Field(i).Type().Underlying()
|
||||
if !hashmapIsBinaryKey(fieldType) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case *types.Array:
|
||||
return hashmapIsBinaryKey(keyType.Elem())
|
||||
default:
|
||||
@@ -268,68 +228,400 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
|
||||
// We know that hashmapIsBinaryKey is true, so we only have to handle those types that can show up there.
|
||||
// To zero all undefined bytes, we iterate over all the fields in the type. For each element, compute the
|
||||
// offset of that element. If it's Basic type, there are no internal padding bytes. For compound types, we recurse to ensure
|
||||
// we handle nested types. Next, we determine if there are any padding bytes before the next
|
||||
// element and zero those as well.
|
||||
// hashmapKeyHashSignature returns the Go type signature for hashmap key hash
|
||||
// functions: func(key unsafe.Pointer, size, seed uintptr) uint32
|
||||
func hashmapKeyHashSignature() *types.Signature {
|
||||
return types.NewSignatureType(nil, nil, nil,
|
||||
types.NewTuple(
|
||||
types.NewVar(token.NoPos, nil, "key", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uintptr]),
|
||||
types.NewVar(token.NoPos, nil, "seed", types.Typ[types.Uintptr]),
|
||||
),
|
||||
types.NewTuple(
|
||||
types.NewVar(token.NoPos, nil, "", types.Typ[types.Uint32]),
|
||||
),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
// hashmapKeyEqualSignature returns the Go type signature for hashmap key equal
|
||||
// functions: func(x, y unsafe.Pointer, n uintptr) bool
|
||||
func hashmapKeyEqualSignature() *types.Signature {
|
||||
return types.NewSignatureType(nil, nil, nil,
|
||||
types.NewTuple(
|
||||
types.NewVar(token.NoPos, nil, "x", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "y", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "n", types.Typ[types.Uintptr]),
|
||||
),
|
||||
types.NewTuple(
|
||||
types.NewVar(token.NoPos, nil, "", types.Typ[types.Bool]),
|
||||
),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
switch llvmType.TypeKind() {
|
||||
case llvm.IntegerTypeKind:
|
||||
// no padding bytes
|
||||
return nil
|
||||
case llvm.PointerTypeKind:
|
||||
// mo padding bytes
|
||||
return nil
|
||||
case llvm.ArrayTypeKind:
|
||||
llvmArrayType := llvmType
|
||||
llvmElemType := llvmType.ElementType()
|
||||
// hashmapKeyFuncName returns a canonical name for a generated hash or equal
|
||||
// function based on the key type's underlying structure. Named types are
|
||||
// replaced with their underlying types so that structurally identical key
|
||||
// types (e.g., struct{i1; str1} and struct{i2; str2} where both i1, i2 are
|
||||
// int and str1, str2 are string) share the same generated function.
|
||||
func hashmapKeyFuncName(prefix string, keyType types.Type) string {
|
||||
return prefix + "." + hashmapCanonicalTypeName(keyType)
|
||||
}
|
||||
|
||||
for i := 0; i < llvmArrayType.ArrayLength(); i++ {
|
||||
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
||||
elemPtr := b.CreateInBoundsGEP(llvmArrayType, ptr, []llvm.Value{zero, idx}, "")
|
||||
|
||||
// zero any padding bytes in this element
|
||||
b.zeroUndefBytes(llvmElemType, elemPtr)
|
||||
// hashmapCanonicalTypeName returns a string representation of the hash/equal
|
||||
// operations needed for a type, stripping named types where the operation does
|
||||
// not depend on the name. Pointer and channel names do not include the element
|
||||
// type because their hash/equal operations only use the pointer word.
|
||||
func hashmapCanonicalTypeName(t types.Type) string {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
return t.Name()
|
||||
case *types.Pointer:
|
||||
return "*"
|
||||
case *types.Chan:
|
||||
switch t.Dir() {
|
||||
case types.SendRecv:
|
||||
return "chan"
|
||||
case types.SendOnly:
|
||||
return "chan<-"
|
||||
case types.RecvOnly:
|
||||
return "<-chan"
|
||||
}
|
||||
|
||||
case llvm.StructTypeKind:
|
||||
llvmStructType := llvmType
|
||||
numFields := llvmStructType.StructElementTypesCount()
|
||||
llvmElementTypes := llvmStructType.StructElementTypes()
|
||||
|
||||
for i := 0; i < numFields; i++ {
|
||||
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
|
||||
elemPtr := b.CreateInBoundsGEP(llvmStructType, ptr, []llvm.Value{zero, idx}, "")
|
||||
|
||||
// zero any padding bytes in this field
|
||||
llvmElemType := llvmElementTypes[i]
|
||||
b.zeroUndefBytes(llvmElemType, elemPtr)
|
||||
|
||||
// zero any padding bytes before the next field, if any
|
||||
offset := b.targetData.ElementOffset(llvmStructType, i)
|
||||
storeSize := b.targetData.TypeStoreSize(llvmElemType)
|
||||
fieldEndOffset := offset + storeSize
|
||||
|
||||
var nextOffset uint64
|
||||
if i < numFields-1 {
|
||||
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
|
||||
} else {
|
||||
// Last field? Next offset is the total size of the allocate struct.
|
||||
nextOffset = b.targetData.TypeAllocSize(llvmStructType)
|
||||
}
|
||||
|
||||
if fieldEndOffset != nextOffset {
|
||||
n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
|
||||
llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
|
||||
paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), elemPtr, []llvm.Value{llvmStoreSize}, "")
|
||||
b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
|
||||
}
|
||||
case *types.Interface:
|
||||
if t.NumMethods() == 0 {
|
||||
return "interface{}"
|
||||
}
|
||||
return t.String()
|
||||
case *types.Struct:
|
||||
var s strings.Builder
|
||||
s.WriteString("struct{")
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
if i > 0 {
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString(hashmapCanonicalTypeName(t.Field(i).Type()))
|
||||
}
|
||||
return s.String() + "}"
|
||||
case *types.Array:
|
||||
return fmt.Sprintf("[%d]%s", t.Len(), hashmapCanonicalTypeName(t.Elem()))
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
// getOrGenerateKeyHashFunc returns an LLVM function that computes the hash
|
||||
// of a key of the given type. The function is generated on first call and
|
||||
// cached in the module.
|
||||
func (b *builder) getOrGenerateKeyHashFunc(keyType types.Type) llvm.Value {
|
||||
name := hashmapKeyFuncName("hashmapKeyHash", keyType)
|
||||
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
|
||||
return fn
|
||||
}
|
||||
|
||||
return nil
|
||||
// Create the LLVM function type:
|
||||
// (key ptr, size uintptr, seed uintptr, context ptr) -> i32
|
||||
fnType := llvm.FunctionType(b.ctx.Int32Type(), []llvm.Type{
|
||||
b.dataPtrType, b.uintptrType, b.uintptrType, b.dataPtrType,
|
||||
}, false)
|
||||
fn := llvm.AddFunction(b.mod, name, fnType)
|
||||
fn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
fn.SetUnnamedAddr(true)
|
||||
b.addStandardAttributes(fn)
|
||||
|
||||
// Generate the function body.
|
||||
savedBlock := b.GetInsertBlock()
|
||||
defer b.SetInsertPointAtEnd(savedBlock)
|
||||
|
||||
entry := b.ctx.AddBasicBlock(fn, "entry")
|
||||
b.SetInsertPointAtEnd(entry)
|
||||
|
||||
keyPtr := fn.Param(0)
|
||||
seed := fn.Param(2)
|
||||
llvmKeyType := b.getLLVMType(keyType)
|
||||
hash := b.generateKeyHash(keyType, llvmKeyType, keyPtr, seed)
|
||||
b.CreateRet(hash)
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
// getOrGenerateKeyEqualFunc returns an LLVM function that compares two keys
|
||||
// of the given type for equality. The function is generated on first call
|
||||
// and cached in the module.
|
||||
func (b *builder) getOrGenerateKeyEqualFunc(keyType types.Type) llvm.Value {
|
||||
name := hashmapKeyFuncName("hashmapKeyEqual", keyType)
|
||||
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
|
||||
return fn
|
||||
}
|
||||
|
||||
// Create the LLVM function type:
|
||||
// (x ptr, y ptr, n uintptr, context ptr) -> i1
|
||||
fnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{
|
||||
b.dataPtrType, b.dataPtrType, b.uintptrType, b.dataPtrType,
|
||||
}, false)
|
||||
fn := llvm.AddFunction(b.mod, name, fnType)
|
||||
fn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
fn.SetUnnamedAddr(true)
|
||||
b.addStandardAttributes(fn)
|
||||
|
||||
// Generate the function body.
|
||||
savedBlock := b.GetInsertBlock()
|
||||
defer b.SetInsertPointAtEnd(savedBlock)
|
||||
|
||||
entry := b.ctx.AddBasicBlock(fn, "entry")
|
||||
b.SetInsertPointAtEnd(entry)
|
||||
|
||||
xPtr := fn.Param(0)
|
||||
yPtr := fn.Param(1)
|
||||
llvmKeyType := b.getLLVMType(keyType)
|
||||
result := b.generateKeyEqual(keyType, llvmKeyType, xPtr, yPtr, fn)
|
||||
b.CreateRet(result)
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
// generateKeyHash generates IR that hashes a key value. Returns the i32 hash.
|
||||
func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, keyPtr llvm.Value, seed llvm.Value) llvm.Value {
|
||||
switch keyType := keyType.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
if keyType.Info()&types.IsString != 0 {
|
||||
// Hash the string contents. The size parameter is unused by
|
||||
// hashmapStringPtrHash (it dereferences the string header to
|
||||
// get the actual length), but we pass it for signature
|
||||
// consistency with other hash functions.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hashmapStringPtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||
}
|
||||
if keyType.Info()&types.IsFloat != 0 {
|
||||
// Float hash: normalizes -0 to +0 before hashing.
|
||||
if keyType.Kind() == types.Float32 {
|
||||
return b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{keyPtr, seed}, "hash")
|
||||
}
|
||||
return b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{keyPtr, seed}, "hash")
|
||||
}
|
||||
if keyType.Info()&types.IsComplex != 0 {
|
||||
// Complex hash: hash real and imaginary parts as floats.
|
||||
if keyType.Kind() == types.Complex64 {
|
||||
realPtr := keyPtr
|
||||
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
|
||||
llvm.ConstInt(b.uintptrType, 4, false),
|
||||
}, "")
|
||||
realHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{realPtr, seed}, "hash.real")
|
||||
imagHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
|
||||
return b.CreateXor(realHash, imagHash, "")
|
||||
}
|
||||
realPtr := keyPtr
|
||||
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
|
||||
llvm.ConstInt(b.uintptrType, 8, false),
|
||||
}, "")
|
||||
realHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{realPtr, seed}, "hash.real")
|
||||
imagHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
|
||||
return b.CreateXor(realHash, imagHash, "")
|
||||
}
|
||||
// Integer/boolean: hash the raw bytes.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||
case *types.Pointer, *types.Chan:
|
||||
// Pointers and channels: hash as raw pointer-sized bytes.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||
case *types.Interface:
|
||||
// Interface: use runtime reflection-based hash.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||
case *types.Struct:
|
||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 0; i < keyType.NumFields(); i++ {
|
||||
if keyType.Field(i).Name() == "_" {
|
||||
continue // blank fields are ignored in Go equality
|
||||
}
|
||||
fieldType := keyType.Field(i).Type()
|
||||
llvmFieldType := b.getLLVMType(fieldType)
|
||||
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
|
||||
continue // skip zero-sized fields
|
||||
}
|
||||
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
|
||||
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
|
||||
hash = b.CreateXor(hash, fieldHash, "")
|
||||
}
|
||||
return hash
|
||||
case *types.Array:
|
||||
elemType := keyType.Elem()
|
||||
llvmElemType := b.getLLVMType(elemType)
|
||||
arrayLen := keyType.Len()
|
||||
if hashmapIsBinaryKey(elemType) {
|
||||
// All elements are binary-comparable; hash the entire array as raw bytes.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||
}
|
||||
if arrayLen == 0 {
|
||||
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
}
|
||||
if arrayLen <= hashArrayUnrollLimit {
|
||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 0; i < int(arrayLen); i++ {
|
||||
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||
hash = b.CreateXor(hash, elemHash, "")
|
||||
}
|
||||
return hash
|
||||
}
|
||||
initHash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
|
||||
loopEntry := b.GetInsertBlock()
|
||||
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.body")
|
||||
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.done")
|
||||
|
||||
b.CreateBr(loopBody)
|
||||
b.SetInsertPointAtEnd(loopBody)
|
||||
|
||||
phiI := b.CreatePHI(b.uintptrType, "i")
|
||||
phiHash := b.CreatePHI(b.ctx.Int32Type(), "hash.acc")
|
||||
|
||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
|
||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||
newHash := b.CreateXor(phiHash, elemHash, "")
|
||||
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
||||
b.CreateCondBr(cond, loopBody, loopDone)
|
||||
|
||||
bodyEnd := b.GetInsertBlock()
|
||||
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
|
||||
[]llvm.BasicBlock{loopEntry, bodyEnd})
|
||||
phiHash.AddIncoming([]llvm.Value{initHash, newHash},
|
||||
[]llvm.BasicBlock{loopEntry, bodyEnd})
|
||||
|
||||
b.SetInsertPointAtEnd(loopDone)
|
||||
return newHash
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled key type for hash generation: %T", keyType))
|
||||
}
|
||||
}
|
||||
|
||||
// generateKeyEqual generates IR that compares two key values for equality.
|
||||
// Returns an i1 result.
|
||||
func (b *builder) generateKeyEqual(keyType types.Type, llvmKeyType llvm.Type, xPtr, yPtr llvm.Value, fn llvm.Value) llvm.Value {
|
||||
switch keyType := keyType.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
if keyType.Info()&types.IsString != 0 {
|
||||
// Compare strings: load both string headers and compare.
|
||||
xStr := b.CreateLoad(llvmKeyType, xPtr, "x.str")
|
||||
yStr := b.CreateLoad(llvmKeyType, yPtr, "y.str")
|
||||
return b.createRuntimeCall("stringEqual", []llvm.Value{xStr, yStr}, "eq")
|
||||
}
|
||||
if keyType.Info()&types.IsFloat != 0 {
|
||||
// Float equality: fcmp oeq handles -0==+0 (true) and NaN==NaN (false).
|
||||
xVal := b.CreateLoad(llvmKeyType, xPtr, "x.float")
|
||||
yVal := b.CreateLoad(llvmKeyType, yPtr, "y.float")
|
||||
return b.CreateFCmp(llvm.FloatOEQ, xVal, yVal, "eq")
|
||||
}
|
||||
if keyType.Info()&types.IsComplex != 0 {
|
||||
// Complex equality: both real and imaginary parts must be equal.
|
||||
var floatType llvm.Type
|
||||
if keyType.Kind() == types.Complex64 {
|
||||
floatType = b.ctx.FloatType()
|
||||
} else {
|
||||
floatType = b.ctx.DoubleType()
|
||||
}
|
||||
floatSize := b.targetData.TypeAllocSize(floatType)
|
||||
imagOffset := llvm.ConstInt(b.uintptrType, floatSize, false)
|
||||
// Real parts
|
||||
xReal := b.CreateLoad(floatType, xPtr, "x.real")
|
||||
yReal := b.CreateLoad(floatType, yPtr, "y.real")
|
||||
realEq := b.CreateFCmp(llvm.FloatOEQ, xReal, yReal, "eq.real")
|
||||
// Imaginary parts
|
||||
xImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), xPtr, []llvm.Value{imagOffset}, "")
|
||||
yImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), yPtr, []llvm.Value{imagOffset}, "")
|
||||
xImag := b.CreateLoad(floatType, xImagPtr, "x.imag")
|
||||
yImag := b.CreateLoad(floatType, yImagPtr, "y.imag")
|
||||
imagEq := b.CreateFCmp(llvm.FloatOEQ, xImag, yImag, "eq.imag")
|
||||
return b.CreateAnd(realEq, imagEq, "")
|
||||
}
|
||||
// Integer/boolean: compare raw bytes.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
|
||||
case *types.Pointer, *types.Chan:
|
||||
// Pointers and channels: compare as raw pointer-sized bytes.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
|
||||
case *types.Interface:
|
||||
// Interface: use runtime interface equality.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("hashmapInterfaceEqual", []llvm.Value{xPtr, yPtr, size}, "eq")
|
||||
case *types.Struct:
|
||||
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false) // start with true
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 0; i < keyType.NumFields(); i++ {
|
||||
if keyType.Field(i).Name() == "_" {
|
||||
continue // blank fields are ignored in Go equality
|
||||
}
|
||||
fieldType := keyType.Field(i).Type()
|
||||
llvmFieldType := b.getLLVMType(fieldType)
|
||||
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
|
||||
continue // skip zero-sized fields
|
||||
}
|
||||
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
|
||||
xFieldPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
|
||||
yFieldPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
|
||||
fieldEq := b.generateKeyEqual(fieldType, llvmFieldType, xFieldPtr, yFieldPtr, fn)
|
||||
result = b.CreateAnd(result, fieldEq, "")
|
||||
}
|
||||
return result
|
||||
case *types.Array:
|
||||
elemType := keyType.Elem()
|
||||
llvmElemType := b.getLLVMType(elemType)
|
||||
arrayLen := keyType.Len()
|
||||
if hashmapIsBinaryKey(elemType) {
|
||||
// All elements are binary-comparable; compare the entire array.
|
||||
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
|
||||
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
|
||||
}
|
||||
if arrayLen == 0 {
|
||||
return llvm.ConstInt(b.ctx.Int1Type(), 1, false)
|
||||
}
|
||||
if arrayLen <= hashArrayUnrollLimit {
|
||||
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false)
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 0; i < int(arrayLen); i++ {
|
||||
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
||||
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
|
||||
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
|
||||
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
|
||||
result = b.CreateAnd(result, elemEq, "")
|
||||
}
|
||||
return result
|
||||
}
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
|
||||
loopEntry := b.GetInsertBlock()
|
||||
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.body")
|
||||
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.done")
|
||||
|
||||
b.CreateBr(loopBody)
|
||||
b.SetInsertPointAtEnd(loopBody)
|
||||
|
||||
phiI := b.CreatePHI(b.uintptrType, "i")
|
||||
|
||||
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, phiI}, "")
|
||||
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, phiI}, "")
|
||||
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
|
||||
|
||||
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||
atEnd := b.CreateICmp(llvm.IntUGE, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
||||
exitLoop := b.CreateOr(atEnd, b.CreateNot(elemEq, ""), "")
|
||||
b.CreateCondBr(exitLoop, loopDone, loopBody)
|
||||
|
||||
bodyEnd := b.GetInsertBlock()
|
||||
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
|
||||
[]llvm.BasicBlock{loopEntry, bodyEnd})
|
||||
|
||||
b.SetInsertPointAtEnd(loopDone)
|
||||
return elemEq
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled key type for equal generation: %T", keyType))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -29,8 +29,7 @@ func (s *stdSizes) Alignof(T types.Type) int64 {
|
||||
// is the largest of the values unsafe.Alignof(x.f) for each
|
||||
// field f of x, but at least 1."
|
||||
max := int64(1)
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
f := t.Field(i)
|
||||
for f := range t.Fields() {
|
||||
if a := s.Alignof(f.Type()); a > max {
|
||||
max = a
|
||||
}
|
||||
|
||||
+167
-33
@@ -8,6 +8,8 @@ import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -34,6 +36,7 @@ type functionInfo struct {
|
||||
interrupt bool // go:interrupt
|
||||
nobounds bool // go:nobounds
|
||||
noescape bool // go:noescape
|
||||
noheap bool // go:noheap
|
||||
variadic bool // go:variadic (CGo only)
|
||||
inline inlineType // go:inline
|
||||
}
|
||||
@@ -84,8 +87,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
retType = c.getLLVMType(fn.Signature.Results().At(0).Type())
|
||||
} else {
|
||||
results := make([]llvm.Type, 0, fn.Signature.Results().Len())
|
||||
for i := 0; i < fn.Signature.Results().Len(); i++ {
|
||||
results = append(results, c.getLLVMType(fn.Signature.Results().At(i).Type()))
|
||||
for v := range fn.Signature.Results().Variables() {
|
||||
results = append(results, c.getLLVMType(v.Type()))
|
||||
}
|
||||
retType = c.ctx.StructType(results, false)
|
||||
}
|
||||
@@ -142,6 +145,11 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
|
||||
llvmFn.AddAttributeAtIndex(i+1, nocapture)
|
||||
}
|
||||
if paramInfo.flags¶mIsReadonly != 0 && paramInfo.llvmType.TypeKind() == llvm.PointerTypeKind {
|
||||
// Readonly pointer parameters (like strings) benefit from being marked as readonly.
|
||||
readonly := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)
|
||||
llvmFn.AddAttributeAtIndex(i+1, readonly)
|
||||
}
|
||||
}
|
||||
|
||||
// Set a number of function or parameter attributes, depending on the
|
||||
@@ -154,7 +162,9 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
|
||||
case "internal/abi.NoEscape":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.alloc":
|
||||
case "machine.keepAliveNoEscape", "machine.unsafeNoEscape":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.alloc", "runtime.alloc_noheap", "runtime.alloc_zero":
|
||||
// Tell the optimizer that runtime.alloc is an allocator, meaning that it
|
||||
// returns values that are never null and never alias to an existing value.
|
||||
for _, attrName := range []string{"noalias", "nonnull"} {
|
||||
@@ -177,18 +187,37 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// be modified.
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
case "runtime.sliceCopy":
|
||||
// Copying a slice won't capture any of the parameters.
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("writeonly"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.stringFromBytes":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
case "runtime.stringFromRunes":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
case "runtime.hashmapSet":
|
||||
// The key (param 2) and value (param 3) pointers are only read via
|
||||
// memcpy/hash/equal and are never captured. The indirect calls
|
||||
// through m.keyHash and m.keyEqual function pointers prevent LLVM's
|
||||
// functionattrs pass from inferring this automatically.
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.hashmapGet":
|
||||
// The key (param 2) is read-only and never captured.
|
||||
// The value (param 3) is written to (receives the result) but never captured.
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.hashmapDelete":
|
||||
// The key (param 2) is read-only and never captured.
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.hashmapGenericSet":
|
||||
// Same as hashmapBinarySet: key (param 2) and value (param 3) are
|
||||
// not captured.
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.hashmapGenericGet":
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.hashmapGenericDelete":
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.trackPointer":
|
||||
// This function is necessary for tracking pointers on the stack in a
|
||||
// portable way (see gc_stack_portable.go). Indicate to the optimizer
|
||||
@@ -295,6 +324,12 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
linkName: f.RelString(nil),
|
||||
}
|
||||
|
||||
// RelString is not unique for local type arguments, so add a suffix
|
||||
// when needed.
|
||||
if suffix := c.localTypeArgsSuffix(f); suffix != "" {
|
||||
info.linkName += suffix
|
||||
}
|
||||
|
||||
// Check for a few runtime functions that are treated specially.
|
||||
if info.linkName == "runtime.wasmEntryReactor" && c.BuildMode == "c-shared" {
|
||||
info.linkName = "_initialize"
|
||||
@@ -319,6 +354,42 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *compilerContext) localTypeArgsSuffix(f *ssa.Function) string {
|
||||
typeArgs := f.TypeArgs()
|
||||
if len(typeArgs) == 0 {
|
||||
return ""
|
||||
}
|
||||
var hasLocal bool
|
||||
parts := make([]string, len(typeArgs))
|
||||
for i, ta := range typeArgs {
|
||||
name, isLocal := c.getTypeCodeName(ta)
|
||||
if isLocal {
|
||||
hasLocal = true
|
||||
}
|
||||
// A function-local type alias (e.g. `type F = float64` inside a
|
||||
// function body) is invisible to getTypeCodeName because it calls
|
||||
// types.Unalias first. Two callers that use distinct aliases with
|
||||
// the same name (e.g. Go 1.27's internal/strconv.ftoa32 and ftoa64
|
||||
// both declare a local `type F = ...`) then produce identical
|
||||
// RelStrings for their shortFloat[F] instantiations and collide on
|
||||
// mod.NamedFunction. Treat these aliases as local so the suffix
|
||||
// disambiguates them.
|
||||
if alias, ok := ta.(*types.Alias); ok {
|
||||
if obj := alias.Obj(); obj.Pkg() != nil && obj.Parent() != obj.Pkg().Scope() {
|
||||
hasLocal = true
|
||||
pos := c.program.Fset.PositionFor(obj.Pos(), false)
|
||||
parts[i] = fmt.Sprintf("%s$alias:%s:%d:%d", name, filepath.Base(pos.Filename), pos.Line, pos.Column)
|
||||
continue
|
||||
}
|
||||
}
|
||||
parts[i] = name
|
||||
}
|
||||
if !hasLocal {
|
||||
return ""
|
||||
}
|
||||
return "$localtype:" + strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
|
||||
// //export or //go:noinline.
|
||||
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
@@ -345,6 +416,51 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
}
|
||||
}
|
||||
|
||||
// Also scan file-level //go:linkname directives. These appear as
|
||||
// free-standing comments in *ast.File.Comments (not attached to any
|
||||
// declaration), and are used by modern golang.org/x/sys/unix and others.
|
||||
// Function-attached directives (above) take precedence — we only add
|
||||
// file-level ones if no doc-comment linkname was found for this function.
|
||||
//
|
||||
// TODO: the hasUnsafeImport gate enforced downstream (see the
|
||||
// //go:linkname case below) is package-level. gc enforces it per
|
||||
// file, on the file containing the directive. For file-level
|
||||
// linknames this is more important than for function-attached ones,
|
||||
// because the directive can live in a file separate from the
|
||||
// function. A stricter implementation would check whether the file
|
||||
// returned by fileForFunc imports "unsafe", not whether any file in
|
||||
// the package does.
|
||||
hasFunctionLinkname := false
|
||||
for _, comment := range pragmas {
|
||||
if strings.HasPrefix(comment.Text, "//go:linkname ") {
|
||||
parts := strings.Fields(comment.Text)
|
||||
if len(parts) == 3 && parts[1] == f.Name() {
|
||||
hasFunctionLinkname = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasFunctionLinkname {
|
||||
if file := c.fileForFunc(f); file != nil {
|
||||
for _, group := range file.Comments {
|
||||
// Skip the function's own doc comment — already handled above.
|
||||
if decl, ok := syntax.(*ast.FuncDecl); ok && group == decl.Doc {
|
||||
continue
|
||||
}
|
||||
for _, comment := range group.List {
|
||||
if !strings.HasPrefix(comment.Text, "//go:linkname ") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(comment.Text)
|
||||
if len(parts) != 3 || parts[1] != f.Name() {
|
||||
continue
|
||||
}
|
||||
pragmas = append(pragmas, comment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each pragma.
|
||||
for _, comment := range pragmas {
|
||||
parts := strings.Fields(comment.Text)
|
||||
@@ -362,7 +478,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
info.wasmName = info.linkName
|
||||
info.exported = true
|
||||
case "//go:interrupt":
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) {
|
||||
info.interrupt = true
|
||||
}
|
||||
case "//go:wasm-module":
|
||||
@@ -424,14 +540,14 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
// This is a slightly looser requirement than what gc uses: gc
|
||||
// requires the file to import "unsafe", not the package as a
|
||||
// whole.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) {
|
||||
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) {
|
||||
if len(parts) == 2 && slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) {
|
||||
info.section = parts[1]
|
||||
info.inline = inlineNone
|
||||
}
|
||||
@@ -440,7 +556,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
// runtime functions.
|
||||
// This is somewhat dangerous and thus only imported in packages
|
||||
// that import unsafe.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) {
|
||||
info.nobounds = true
|
||||
}
|
||||
case "//go:noescape":
|
||||
@@ -450,6 +566,9 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
if len(f.Blocks) == 0 {
|
||||
info.noescape = true
|
||||
}
|
||||
case "//go:noheap":
|
||||
// Ensure this function does not allocate on the heap.
|
||||
info.noheap = true
|
||||
case "//go:variadic":
|
||||
// The //go:variadic pragma is emitted by the CGo preprocessing
|
||||
// pass for C variadic functions. This includes both explicit
|
||||
@@ -537,9 +656,9 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
|
||||
hasHostLayout = false // package structs added in go1.23
|
||||
}
|
||||
}
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
ftyp := typ.Field(i).Type()
|
||||
if ftyp.String() == "structs.HostLayout" {
|
||||
for field := range typ.Fields() {
|
||||
ftyp := field.Type()
|
||||
if types.Unalias(ftyp).String() == "structs.HostLayout" {
|
||||
hasHostLayout = true
|
||||
continue
|
||||
}
|
||||
@@ -570,8 +689,8 @@ func getParams(sig *types.Signature) []*types.Var {
|
||||
if sig.Recv() != nil {
|
||||
params = append(params, sig.Recv())
|
||||
}
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
params = append(params, sig.Params().At(i))
|
||||
for v := range sig.Params().Variables() {
|
||||
params = append(params, v)
|
||||
}
|
||||
return params
|
||||
}
|
||||
@@ -636,6 +755,34 @@ type globalInfo struct {
|
||||
section string // go:section
|
||||
}
|
||||
|
||||
// fileForFunc returns the *ast.File that contains the declaration of f, or
|
||||
// nil if it cannot be determined. File-level pragmas are only consulted for
|
||||
// functions in the package currently being compiled — functions imported from
|
||||
// other packages have their file-level pragmas processed when those packages
|
||||
// are compiled.
|
||||
func (c *compilerContext) fileForFunc(f *ssa.Function) *ast.File {
|
||||
if c.loaderPkg == nil || f.Pkg == nil || f.Pkg.Pkg != c.loaderPkg.Pkg {
|
||||
return nil
|
||||
}
|
||||
syntax := f.Syntax()
|
||||
if f.Origin() != nil {
|
||||
syntax = f.Origin().Syntax()
|
||||
}
|
||||
if syntax == nil {
|
||||
return nil
|
||||
}
|
||||
pos := syntax.Pos()
|
||||
if !pos.IsValid() {
|
||||
return nil
|
||||
}
|
||||
for _, file := range c.loaderPkg.Files {
|
||||
if file.FileStart <= pos && pos < file.FileEnd {
|
||||
return file
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadASTComments loads comments on globals from the AST, for use later in the
|
||||
// program. In particular, they are required for //go:extern pragmas on globals.
|
||||
func (c *compilerContext) loadASTComments(pkg *loader.Package) {
|
||||
@@ -674,10 +821,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||
llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName)
|
||||
|
||||
// Set alignment from the //go:align comment.
|
||||
alignment := c.targetData.ABITypeAlignment(llvmType)
|
||||
if info.align > alignment {
|
||||
alignment = info.align
|
||||
}
|
||||
alignment := max(info.align, c.targetData.ABITypeAlignment(llvmType))
|
||||
if alignment <= 0 || alignment&(alignment-1) != 0 {
|
||||
// Check for power-of-two (or 0).
|
||||
// See: https://stackoverflow.com/a/108360
|
||||
@@ -751,7 +895,7 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext,
|
||||
// This is a slightly looser requirement than what gc uses: gc
|
||||
// requires the file to import "unsafe", not the package as a
|
||||
// whole.
|
||||
if hasUnsafeImport(g.Pkg.Pkg) {
|
||||
if slices.Contains(g.Pkg.Pkg.Imports(), types.Unsafe) {
|
||||
info.linkName = parts[2]
|
||||
}
|
||||
}
|
||||
@@ -767,13 +911,3 @@ func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection {
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
// Return true if this package imports "unsafe", false otherwise.
|
||||
func hasUnsafeImport(pkg *types.Package) bool {
|
||||
for _, imp := range pkg.Imports() {
|
||||
if imp == types.Unsafe {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+164
-27
@@ -26,24 +26,25 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
// Constraints will look something like:
|
||||
// "={rax},0,{rdi},{rsi},{rdx},{r10},{r8},{r9},~{rcx},~{r11}"
|
||||
constraints := "={rax},0"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={rax},0")
|
||||
for i, arg := range call.Args[1:] {
|
||||
constraints += "," + [...]string{
|
||||
constraints.WriteString("," + [...]string{
|
||||
"{rdi}",
|
||||
"{rsi}",
|
||||
"{rdx}",
|
||||
"{r10}",
|
||||
"{r8}",
|
||||
"{r9}",
|
||||
}[i]
|
||||
}[i])
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
// rcx and r11 are clobbered by the syscall, so make sure they are not used
|
||||
constraints += ",~{rcx},~{r11}"
|
||||
constraints.WriteString(",~{rcx},~{r11}")
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints.String(), true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "386" && b.GOOS == "linux":
|
||||
@@ -55,34 +56,44 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
// Constraints will look something like:
|
||||
// "={eax},0,{ebx},{ecx},{edx},{esi},{edi},{ebp}"
|
||||
constraints := "={eax},0"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={eax},0")
|
||||
for i, arg := range call.Args[1:] {
|
||||
constraints += "," + [...]string{
|
||||
constraints.WriteString("," + [...]string{
|
||||
"{ebx}",
|
||||
"{ecx}",
|
||||
"{edx}",
|
||||
"{esi}",
|
||||
"{edi}",
|
||||
"{ebp}",
|
||||
}[i]
|
||||
}[i])
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints.String(), true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||
if arch := b.archFamily(); arch != "arm" {
|
||||
// Some targets pretend to be linux/arm for compatibility but aren't
|
||||
// actually such a system. Make sure we emit an error instead of
|
||||
// creating inline assembly that will fail to compile.
|
||||
// See: https://github.com/tinygo-org/tinygo/issues/4959
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "system calls are not supported: target emulates a linux/arm system on "+arch)
|
||||
}
|
||||
|
||||
// Implement the EABI system call convention for Linux.
|
||||
// Source: syscall(2) man page.
|
||||
args := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
// Constraints will look something like:
|
||||
// ={r0},0,{r1},{r2},{r7},~{r3}
|
||||
constraints := "={r0}"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={r0}")
|
||||
for i, arg := range call.Args[1:] {
|
||||
constraints += "," + [...]string{
|
||||
constraints.WriteString("," + [...]string{
|
||||
"0", // tie to output
|
||||
"{r1}",
|
||||
"{r2}",
|
||||
@@ -90,20 +101,20 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{r4}",
|
||||
"{r5}",
|
||||
"{r6}",
|
||||
}[i]
|
||||
}[i])
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
args = append(args, num)
|
||||
argTypes = append(argTypes, b.uintptrType)
|
||||
constraints += ",{r7}" // syscall number
|
||||
constraints.WriteString(",{r7}") // syscall number
|
||||
for i := len(call.Args) - 1; i < 4; i++ {
|
||||
// r0-r3 get clobbered after the syscall returns
|
||||
constraints += ",~{r" + strconv.Itoa(i) + "}"
|
||||
constraints.WriteString(",~{r" + strconv.Itoa(i) + "}")
|
||||
}
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints.String(), true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
||||
@@ -112,31 +123,32 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
argTypes := []llvm.Type{}
|
||||
// Constraints will look something like:
|
||||
// ={x0},0,{x1},{x2},{x8},~{x3},~{x4},~{x5},~{x6},~{x7},~{x16},~{x17}
|
||||
constraints := "={x0}"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={x0}")
|
||||
for i, arg := range call.Args[1:] {
|
||||
constraints += "," + [...]string{
|
||||
constraints.WriteString("," + [...]string{
|
||||
"0", // tie to output
|
||||
"{x1}",
|
||||
"{x2}",
|
||||
"{x3}",
|
||||
"{x4}",
|
||||
"{x5}",
|
||||
}[i]
|
||||
}[i])
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
args = append(args, num)
|
||||
argTypes = append(argTypes, b.uintptrType)
|
||||
constraints += ",{x8}" // syscall number
|
||||
constraints.WriteString(",{x8}") // syscall number
|
||||
for i := len(call.Args) - 1; i < 8; i++ {
|
||||
// x0-x7 may get clobbered during the syscall following the aarch64
|
||||
// calling convention.
|
||||
constraints += ",~{x" + strconv.Itoa(i) + "}"
|
||||
constraints.WriteString(",~{x" + strconv.Itoa(i) + "}")
|
||||
}
|
||||
constraints += ",~{x16},~{x17}" // scratch registers
|
||||
constraints.WriteString(",~{x16},~{x17}") // scratch registers
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints.String(), true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case (b.GOARCH == "mips" || b.GOARCH == "mipsle") && b.GOOS == "linux":
|
||||
@@ -155,7 +167,8 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
// faster and smaller code.
|
||||
args := []llvm.Value{num}
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
constraints := "={$2},={$7},0"
|
||||
var constraints strings.Builder
|
||||
constraints.WriteString("={$2},={$7},0")
|
||||
syscallParams := call.Args[1:]
|
||||
if len(syscallParams) > 7 {
|
||||
// There is one syscall that uses 7 parameters: sync_file_range.
|
||||
@@ -164,7 +177,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
syscallParams = syscallParams[:7]
|
||||
}
|
||||
for i, arg := range syscallParams {
|
||||
constraints += "," + [...]string{
|
||||
constraints.WriteString("," + [...]string{
|
||||
"{$4}", // arg1
|
||||
"{$5}", // arg2
|
||||
"{$6}", // arg3
|
||||
@@ -172,7 +185,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"r", // arg5 on the stack
|
||||
"r", // arg6 on the stack
|
||||
"r", // arg7 on the stack
|
||||
}[i]
|
||||
}[i])
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
@@ -213,10 +226,10 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"addu $$sp, $$sp, 32\n" +
|
||||
".set at\n"
|
||||
}
|
||||
constraints += ",~{$3},~{$4},~{$5},~{$6},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$24},~{$25},~{hi},~{lo},~{memory}"
|
||||
constraints.WriteString(",~{$3},~{$4},~{$5},~{$6},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$24},~{$25},~{hi},~{lo},~{memory}")
|
||||
returnType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false)
|
||||
fnType := llvm.FunctionType(returnType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, true, 0, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints.String(), true, true, 0, false)
|
||||
call := b.CreateCall(fnType, target, args, "")
|
||||
resultCode := b.CreateExtractValue(call, 0, "") // r2
|
||||
errorFlag := b.CreateExtractValue(call, 1, "") // r7
|
||||
@@ -341,6 +354,130 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// createSyscalln emits instructions for the syscall.syscalln function on
|
||||
// Windows. This handles the variadic calling convention used in Go 1.26+:
|
||||
//
|
||||
// func syscalln(fn, n uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
||||
//
|
||||
// The function generates a switch on n to dispatch to the correct fixed-argument
|
||||
// function pointer call with SetLastError(0)/GetLastError() wrapping.
|
||||
func (b *builder) createSyscalln(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
const maxArgs = 18 // Windows syscalls support up to 18 args
|
||||
|
||||
isI386 := strings.HasPrefix(b.Triple, "i386-")
|
||||
|
||||
// Get the function pointer (call.Args[0]) and n (call.Args[1]).
|
||||
fn := b.getValue(call.Args[0], getPos(call))
|
||||
fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
|
||||
n := b.getValue(call.Args[1], getPos(call))
|
||||
|
||||
// Get the variadic args slice (call.Args[2]).
|
||||
// In SSA, the variadic slice is the third argument.
|
||||
var argsPtr llvm.Value
|
||||
if len(call.Args) > 2 {
|
||||
argsSlice := b.getValue(call.Args[2], getPos(call))
|
||||
argsPtr = b.CreateExtractValue(argsSlice, 0, "args.data")
|
||||
} else {
|
||||
argsPtr = llvm.ConstNull(b.dataPtrType)
|
||||
}
|
||||
|
||||
// Prepare SetLastError and GetLastError.
|
||||
setLastError := b.mod.NamedFunction("SetLastError")
|
||||
if setLastError.IsNil() {
|
||||
llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
|
||||
setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
|
||||
if isI386 {
|
||||
setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
}
|
||||
getLastError := b.mod.NamedFunction("GetLastError")
|
||||
if getLastError.IsNil() {
|
||||
llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
|
||||
getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
|
||||
if isI386 {
|
||||
getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
}
|
||||
|
||||
retType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false)
|
||||
|
||||
// Create the merge block where all cases converge.
|
||||
mergeBB := b.insertBasicBlock("syscalln.merge")
|
||||
|
||||
// Create the default (panic) block.
|
||||
panicBB := b.insertBasicBlock("syscalln.panic")
|
||||
|
||||
// Create the switch on n.
|
||||
sw := b.CreateSwitch(n, panicBB, maxArgs+1)
|
||||
|
||||
// We'll collect blocks and values for the PHI node.
|
||||
var incomingVals []llvm.Value
|
||||
var incomingBlocks []llvm.BasicBlock
|
||||
|
||||
// Generate a case for each arg count 0..maxArgs.
|
||||
for i := 0; i <= maxArgs; i++ {
|
||||
caseBB := b.insertBasicBlock("syscalln.case" + strconv.Itoa(i))
|
||||
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), caseBB)
|
||||
b.SetInsertPointAtEnd(caseBB)
|
||||
|
||||
// Load args[0] through args[i-1] from the slice data pointer.
|
||||
var params []llvm.Value
|
||||
var paramTypes []llvm.Type
|
||||
for j := 0; j < i; j++ {
|
||||
gep := b.CreateInBoundsGEP(b.uintptrType, argsPtr, []llvm.Value{
|
||||
llvm.ConstInt(b.ctx.Int32Type(), uint64(j), false),
|
||||
}, "")
|
||||
arg := b.CreateLoad(b.uintptrType, gep, "")
|
||||
params = append(params, arg)
|
||||
paramTypes = append(paramTypes, b.uintptrType)
|
||||
}
|
||||
|
||||
// SetLastError(0)
|
||||
setCall := b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
|
||||
var sp llvm.Value
|
||||
if isI386 {
|
||||
setCall.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
sp = b.readStackPointer()
|
||||
}
|
||||
|
||||
// Call fn(args...)
|
||||
fnType := llvm.FunctionType(b.uintptrType, paramTypes, false)
|
||||
syscallResult := b.CreateCall(fnType, fnPtr, params, "")
|
||||
if isI386 {
|
||||
syscallResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
b.writeStackPointer(sp)
|
||||
}
|
||||
|
||||
// err = GetLastError()
|
||||
errResult := b.CreateCall(getLastError.GlobalValueType(), getLastError, nil, "err")
|
||||
if isI386 {
|
||||
errResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
if b.uintptrType != b.ctx.Int32Type() {
|
||||
errResult = b.CreateZExt(errResult, b.uintptrType, "err.uintptr")
|
||||
}
|
||||
|
||||
// Build {r1, 0, err}
|
||||
result := llvm.ConstNull(retType)
|
||||
result = b.CreateInsertValue(result, syscallResult, 0, "")
|
||||
result = b.CreateInsertValue(result, errResult, 2, "")
|
||||
|
||||
incomingVals = append(incomingVals, result)
|
||||
incomingBlocks = append(incomingBlocks, b.Builder.GetInsertBlock())
|
||||
b.CreateBr(mergeBB)
|
||||
}
|
||||
|
||||
// Panic block for n > maxArgs.
|
||||
b.SetInsertPointAtEnd(panicBB)
|
||||
b.CreateUnreachable()
|
||||
|
||||
// Merge block: PHI node to select the result.
|
||||
b.SetInsertPointAtEnd(mergeBB)
|
||||
phi := b.CreatePHI(retType, "syscalln.result")
|
||||
phi.AddIncoming(incomingVals, incomingBlocks)
|
||||
return phi, nil
|
||||
}
|
||||
|
||||
// createRawSyscallNoError emits instructions for the Linux-specific
|
||||
// syscall.rawSyscallNoError function.
|
||||
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
|
||||
Vendored
+29
-33
@@ -10,33 +10,30 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -50,14 +47,14 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %5
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.divideByZeroPanic(ptr) #1
|
||||
declare void @runtime.divideByZeroPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -67,12 +64,12 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -86,12 +83,12 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %5
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -101,66 +98,66 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #3
|
||||
call void @runtime.divideByZeroPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret float %x.r
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fadd float %x.r, %y.r
|
||||
%1 = fadd float %x.i, %y.i
|
||||
@@ -170,7 +167,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 #2 {
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fsub float %x.r, %y.r
|
||||
%1 = fsub float %x.i, %y.i
|
||||
@@ -180,7 +177,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 #2 {
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fmul float %x.r, %y.r
|
||||
%1 = fmul float %x.i, %y.i
|
||||
@@ -194,19 +191,18 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+21
-25
@@ -6,76 +6,73 @@ target triple = "wasm32-unknown-wasi"
|
||||
%runtime.channelOp = type { ptr, ptr, i32, ptr }
|
||||
%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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.op = alloca %runtime.channelOp, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
|
||||
store i32 3, ptr %chan.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
|
||||
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
|
||||
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3
|
||||
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
|
||||
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #0
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.op = alloca %runtime.channelOp, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
|
||||
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.op = alloca %runtime.channelOp, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
|
||||
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
|
||||
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3
|
||||
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.op = alloca %runtime.channelOp, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
|
||||
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3
|
||||
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
||||
%select.send.value = alloca i32, align 4
|
||||
@@ -88,7 +85,7 @@ entry:
|
||||
store ptr %ch2, ptr %0, align 4
|
||||
%.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12
|
||||
store ptr null, ptr %.repack3, align 4
|
||||
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #4
|
||||
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #3
|
||||
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
|
||||
@@ -105,10 +102,9 @@ select.body: ; preds = %select.next
|
||||
br label %select.done
|
||||
}
|
||||
|
||||
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
|
||||
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #0
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #4 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
+261
-29
@@ -3,32 +3,29 @@ source_filename = "defer.go"
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface }
|
||||
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface, ptr }
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.external(ptr) #2
|
||||
declare void @main.external(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.deferSimple(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%defer.alloca = alloca { i32, ptr }, align 4
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||
store ptr null, ptr %defer.alloca.repack15, align 4
|
||||
store ptr %defer.next, ptr %defer.alloca.repack15, align 4
|
||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
||||
@@ -112,14 +109,14 @@ rundefers.end3: ; preds = %rundefers.loophead6
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
||||
declare ptr @llvm.stacksave.p0() #3
|
||||
declare ptr @llvm.stacksave.p0() #2
|
||||
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(28), ptr, ptr) #1
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(28), ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.printlock(ptr undef) #4
|
||||
call void @runtime.printint32(i32 3, ptr undef) #4
|
||||
@@ -127,29 +124,29 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printlock(ptr) #2
|
||||
declare void @runtime.printlock(ptr) #1
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
declare void @runtime.printint32(i32, ptr) #1
|
||||
|
||||
declare void @runtime.printunlock(ptr) #2
|
||||
declare void @runtime.printunlock(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%defer.alloca2 = alloca { i32, ptr }, align 4
|
||||
%defer.alloca = alloca { i32, ptr }, align 4
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||
store ptr null, ptr %defer.alloca.repack22, align 4
|
||||
store ptr %defer.next, ptr %defer.alloca.repack22, align 4
|
||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||
store i32 1, ptr %defer.alloca2, align 4
|
||||
%defer.alloca2.repack23 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
|
||||
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
|
||||
%defer.alloca2.repack24 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
|
||||
store ptr %defer.alloca, ptr %defer.alloca2.repack24, align 4
|
||||
store ptr %defer.alloca2, ptr %deferPtr, align 4
|
||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
|
||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
||||
@@ -253,7 +250,7 @@ rundefers.end7: ; preds = %rundefers.loophead1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.printlock(ptr undef) #4
|
||||
call void @runtime.printint32(i32 3, ptr undef) #4
|
||||
@@ -262,7 +259,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.printlock(ptr undef) #4
|
||||
call void @runtime.printint32(i32 5, ptr undef) #4
|
||||
@@ -270,9 +267,244 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn }
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
br label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloc.call, align 4
|
||||
%defer.alloc.call.repack1 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
|
||||
store ptr %defer.next, ptr %defer.alloc.call.repack1, align 4
|
||||
%defer.alloc.call.repack3 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
|
||||
store i32 8, ptr %defer.alloc.call.repack3, align 4
|
||||
store ptr %defer.alloc.call, ptr %deferPtr, align 4
|
||||
br label %for.body
|
||||
|
||||
recover: ; preds = %rundefers.end
|
||||
ret void
|
||||
|
||||
lpad: ; No predecessors!
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %rundefers.callback0, %lpad
|
||||
br i1 poison, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
switch i32 poison, label %rundefers.default [
|
||||
i32 0, label %rundefers.callback0
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %recover
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferLoop(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
br label %for.loop
|
||||
|
||||
for.loop: ; preds = %for.body, %entry
|
||||
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
|
||||
%2 = icmp slt i32 %1, 10
|
||||
br i1 %2, label %for.body, label %for.done
|
||||
|
||||
for.body: ; preds = %for.loop
|
||||
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||
%defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloc.call, align 4
|
||||
%defer.alloc.call.repack13 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4
|
||||
store ptr %defer.next, ptr %defer.alloc.call.repack13, align 4
|
||||
%defer.alloc.call.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 8
|
||||
store i32 %1, ptr %defer.alloc.call.repack15, align 4
|
||||
store ptr %defer.alloc.call, ptr %deferPtr, align 4
|
||||
%3 = add i32 %1, 1
|
||||
br label %for.loop
|
||||
|
||||
for.done: ; preds = %for.loop
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %for.done
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
|
||||
%4 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %4, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds nuw i8, ptr %4, i32 4
|
||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||
store ptr %stack.next, ptr %deferPtr, align 4
|
||||
%callback = load i32, ptr %4, align 4
|
||||
switch i32 %callback, label %rundefers.default [
|
||||
i32 0, label %rundefers.callback0
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
%gep = getelementptr inbounds nuw i8, ptr %4, i32 8
|
||||
%param = load i32, ptr %gep, align 4
|
||||
call void @runtime.printlock(ptr undef) #4
|
||||
call void @runtime.printint32(i32 %param, ptr undef) #4
|
||||
call void @runtime.printunlock(ptr undef) #4
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end1
|
||||
ret void
|
||||
|
||||
lpad: ; No predecessors!
|
||||
br label %rundefers.loophead4
|
||||
|
||||
rundefers.loophead4: ; preds = %rundefers.callback010, %lpad
|
||||
br i1 poison, label %rundefers.end1, label %rundefers.loop3
|
||||
|
||||
rundefers.loop3: ; preds = %rundefers.loophead4
|
||||
switch i32 poison, label %rundefers.default2 [
|
||||
i32 0, label %rundefers.callback010
|
||||
]
|
||||
|
||||
rundefers.callback010: ; preds = %rundefers.loop3
|
||||
br label %rundefers.loophead4
|
||||
|
||||
rundefers.default2: ; preds = %rundefers.loop3
|
||||
unreachable
|
||||
|
||||
rundefers.end1: ; preds = %rundefers.loophead4
|
||||
br label %recover
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%defer.alloca = alloca { i32, ptr, i32 }, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
br label %for.loop
|
||||
|
||||
for.loop: ; preds = %for.body, %entry
|
||||
%1 = phi i32 [ 0, %entry ], [ %3, %for.body ]
|
||||
%2 = icmp slt i32 %1, 10
|
||||
br i1 %2, label %for.body, label %for.done
|
||||
|
||||
for.body: ; preds = %for.loop
|
||||
%3 = add i32 %1, 1
|
||||
br label %for.loop
|
||||
|
||||
for.done: ; preds = %for.loop
|
||||
%defer.next = load ptr, ptr %deferPtr, align 4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack16 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
|
||||
store ptr %defer.next, ptr %defer.alloca.repack16, align 4
|
||||
%defer.alloca.repack18 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 8
|
||||
store i32 1, ptr %defer.alloca.repack18, align 4
|
||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||
br label %for.loop1
|
||||
|
||||
for.loop1: ; preds = %for.body2, %for.done
|
||||
%4 = phi i32 [ 0, %for.done ], [ %6, %for.body2 ]
|
||||
%5 = icmp slt i32 %4, 10
|
||||
br i1 %5, label %for.body2, label %for.done3
|
||||
|
||||
for.body2: ; preds = %for.loop1
|
||||
%6 = add i32 %4, 1
|
||||
br label %for.loop1
|
||||
|
||||
for.done3: ; preds = %for.loop1
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %for.done3
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %rundefers.callback0, %rundefers.block
|
||||
%7 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %7, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds nuw i8, ptr %7, i32 4
|
||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||
store ptr %stack.next, ptr %deferPtr, align 4
|
||||
%callback = load i32, ptr %7, align 4
|
||||
switch i32 %callback, label %rundefers.default [
|
||||
i32 0, label %rundefers.callback0
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
%gep = getelementptr inbounds nuw i8, ptr %7, i32 8
|
||||
%param = load i32, ptr %gep, align 4
|
||||
call void @runtime.printlock(ptr undef) #4
|
||||
call void @runtime.printint32(i32 %param, ptr undef) #4
|
||||
call void @runtime.printunlock(ptr undef) #4
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end4
|
||||
ret void
|
||||
|
||||
lpad: ; No predecessors!
|
||||
br label %rundefers.loophead7
|
||||
|
||||
rundefers.loophead7: ; preds = %rundefers.callback013, %lpad
|
||||
br i1 poison, label %rundefers.end4, label %rundefers.loop6
|
||||
|
||||
rundefers.loop6: ; preds = %rundefers.loophead7
|
||||
switch i32 poison, label %rundefers.default5 [
|
||||
i32 0, label %rundefers.callback013
|
||||
]
|
||||
|
||||
rundefers.callback013: ; preds = %rundefers.loop6
|
||||
br label %rundefers.loophead7
|
||||
|
||||
rundefers.default5: ; preds = %rundefers.loop6
|
||||
unreachable
|
||||
|
||||
rundefers.end4: ; preds = %rundefers.loophead7
|
||||
br label %recover
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { nocallback nofree nosync nounwind willreturn }
|
||||
attributes #3 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #4 = { nounwind }
|
||||
attributes #5 = { nounwind returns_twice }
|
||||
|
||||
Vendored
+20
@@ -18,3 +18,23 @@ func deferMultiple() {
|
||||
}()
|
||||
external()
|
||||
}
|
||||
|
||||
func deferInfiniteLoop() {
|
||||
for {
|
||||
defer print(8)
|
||||
}
|
||||
}
|
||||
|
||||
func deferLoop() {
|
||||
for i := 0; i < 10; i++ {
|
||||
defer print(i)
|
||||
}
|
||||
}
|
||||
|
||||
func deferBetweenLoops() {
|
||||
for i := 0; i < 10; i++ {
|
||||
}
|
||||
defer print(1)
|
||||
for i := 0; i < 10; i++ {
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+12
-16
@@ -3,19 +3,16 @@ source_filename = "float.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||
target 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -27,25 +24,25 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret float 0x41F0000000000000
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 -1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 {
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = uitofp i32 %v to float
|
||||
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
||||
@@ -55,7 +52,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -68,7 +65,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 2.550000e+02
|
||||
@@ -80,7 +77,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%abovemin = fcmp oge float %v, -1.280000e+02
|
||||
%belowmax = fcmp ole float %v, 1.270000e+02
|
||||
@@ -93,6 +90,5 @@ entry:
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
|
||||
Vendored
+11
-15
@@ -3,48 +3,44 @@ source_filename = "func.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||
target 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 {
|
||||
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) #3
|
||||
call void %callback.funcptr(i32 3, ptr %callback.context) #2
|
||||
ret void
|
||||
|
||||
fpcall.throw: ; preds = %entry
|
||||
call void @runtime.nilPanic(ptr undef) #3
|
||||
call void @runtime.nilPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.nilPanic(ptr) #1
|
||||
declare void @runtime.nilPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+8
@@ -24,6 +24,10 @@ var (
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
}
|
||||
struct5 *struct {
|
||||
x *byte
|
||||
y [30]uintptr
|
||||
}
|
||||
|
||||
slice1 []byte
|
||||
slice2 []*int
|
||||
@@ -58,6 +62,10 @@ func newStruct() {
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
})
|
||||
struct5 = new(struct {
|
||||
x *byte
|
||||
y [30]uintptr
|
||||
})
|
||||
}
|
||||
|
||||
func newFuncValue() *func() {
|
||||
|
||||
Vendored
+26
-19
@@ -16,27 +16,25 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.struct2 = hidden global ptr null, align 4
|
||||
@main.struct3 = hidden global ptr null, align 4
|
||||
@main.struct4 = hidden global ptr null, align 4
|
||||
@main.struct5 = hidden global ptr null, align 4
|
||||
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@"runtime/gc.layout:62-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" }
|
||||
@"runtime/gc.layout:62-0100000000000020" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0100000000000000" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
@@ -54,8 +52,11 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
@@ -71,26 +72,32 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new = call align 1 ptr @runtime.alloc_zero(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 align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.struct2, align 4
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000020", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.struct3, align 4
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000000", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.struct4, align 4
|
||||
%new4 = call align 4 dereferenceable(124) ptr @runtime.alloc(i32 124, ptr nonnull inttoptr (i32 127 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new4, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new4, ptr @main.struct5, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc_zero(i32, ptr, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
|
||||
@@ -99,7 +106,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
@@ -121,7 +128,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||
@@ -135,7 +142,7 @@ entry:
|
||||
ret %runtime._interface %1
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+100
-212
@@ -1,259 +1,147 @@
|
||||
; ModuleID = 'generics.go'
|
||||
source_filename = "generics.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%"main.Point[int]" = type { i32, i32 }
|
||||
%"main.Point[float32]" = type { float, float }
|
||||
%"main.Point[int]" = type { i32, i32 }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.main(i8* %context) unnamed_addr #1 {
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%bi = alloca %"main.Point[int]", align 8
|
||||
%ai = alloca %"main.Point[int]", align 8
|
||||
%bf = alloca %"main.Point[float32]", align 8
|
||||
%af = alloca %"main.Point[float32]", align 8
|
||||
%af.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %af.repack, align 8
|
||||
%af.repack1 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %af.repack1, align 4
|
||||
%0 = bitcast %"main.Point[float32]"* %af to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%bf.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %bf.repack, align 8
|
||||
%bf.repack2 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %bf.repack2, align 4
|
||||
%1 = bitcast %"main.Point[float32]"* %bf to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
||||
%.unpack = load float, float* %.elt, align 8
|
||||
%.elt3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
||||
%.unpack4 = load float, float* %.elt3, align 4
|
||||
%.elt5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
||||
%.unpack6 = load float, float* %.elt5, align 8
|
||||
%.elt7 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
||||
%.unpack8 = load float, float* %.elt7, align 4
|
||||
%2 = call %"main.Point[float32]" @"main.Add[float32]"(float %.unpack, float %.unpack4, float %.unpack6, float %.unpack8, i8* undef)
|
||||
%ai.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
||||
store i32 0, i32* %ai.repack, align 8
|
||||
%ai.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
||||
store i32 0, i32* %ai.repack9, align 4
|
||||
%3 = bitcast %"main.Point[int]"* %ai to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %3, i8* undef) #2
|
||||
%bi.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
||||
store i32 0, i32* %bi.repack, align 8
|
||||
%bi.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
||||
store i32 0, i32* %bi.repack10, align 4
|
||||
%4 = bitcast %"main.Point[int]"* %bi to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %4, i8* undef) #2
|
||||
%.elt11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
||||
%.unpack12 = load i32, i32* %.elt11, align 8
|
||||
%.elt13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
||||
%.unpack14 = load i32, i32* %.elt13, align 4
|
||||
%.elt15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
||||
%.unpack16 = load i32, i32* %.elt15, align 8
|
||||
%.elt17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
||||
%.unpack18 = load i32, i32* %.elt17, align 4
|
||||
%5 = call %"main.Point[int]" @"main.Add[int]"(i32 %.unpack12, i32 %.unpack14, i32 %.unpack16, i32 %.unpack18, i8* undef)
|
||||
%0 = call %"main.Point[float32]" @"main.Add[float32]"(float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, ptr undef)
|
||||
%1 = call %"main.Point[int]" @"main.Add[int]"(i32 0, i32 0, i32 0, i32 0, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, i8* %context) unnamed_addr #1 {
|
||||
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%complit = alloca %"main.Point[float32]", align 8
|
||||
%b = alloca %"main.Point[float32]", align 8
|
||||
%a = alloca %"main.Point[float32]", align 8
|
||||
%a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %a.repack, align 8
|
||||
%a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %a.repack9, align 4
|
||||
%0 = bitcast %"main.Point[float32]"* %a to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
store float %a.X, float* %a.repack10, align 8
|
||||
%a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
store float %a.Y, float* %a.repack11, align 4
|
||||
%b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %b.repack, align 8
|
||||
%b.repack13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %b.repack13, align 4
|
||||
%1 = bitcast %"main.Point[float32]"* %b to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%b.repack14 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
store float %b.X, float* %b.repack14, align 8
|
||||
%b.repack15 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
store float %b.Y, float* %b.repack15, align 4
|
||||
call void @main.checkSize(i32 4, i8* undef) #2
|
||||
call void @main.checkSize(i32 8, i8* undef) #2
|
||||
%complit.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %complit.repack, align 8
|
||||
%complit.repack17 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %complit.repack17, align 4
|
||||
%2 = bitcast %"main.Point[float32]"* %complit to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
||||
%3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
%stackalloc = alloca i8, align 1
|
||||
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store float %a.X, ptr %a, align 4
|
||||
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4
|
||||
store float %a.Y, ptr %a.repack5, align 4
|
||||
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store float %b.X, ptr %b, align 4
|
||||
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4
|
||||
store float %b.Y, ptr %b.repack7, align 4
|
||||
call void @main.checkSize(i32 4, ptr undef) #3
|
||||
call void @main.checkSize(i32 8, ptr undef) #3
|
||||
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
|
||||
br i1 false, label %deref.throw, label %deref.next
|
||||
|
||||
deref.next: ; preds = %entry
|
||||
br i1 false, label %deref.throw1, label %deref.next2
|
||||
br i1 false, label %deref.throw, label %deref.next1
|
||||
|
||||
deref.next2: ; preds = %deref.next
|
||||
%4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
%5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
%6 = load float, float* %5, align 8
|
||||
%7 = load float, float* %4, align 8
|
||||
%8 = fadd float %6, %7
|
||||
br i1 false, label %deref.throw3, label %deref.next4
|
||||
deref.next1: ; preds = %deref.next
|
||||
%0 = load float, ptr %a, align 4
|
||||
%1 = load float, ptr %b, align 4
|
||||
%2 = fadd float %0, %1
|
||||
br i1 false, label %deref.throw, label %deref.next2
|
||||
|
||||
deref.next4: ; preds = %deref.next2
|
||||
br i1 false, label %deref.throw5, label %deref.next6
|
||||
deref.next2: ; preds = %deref.next1
|
||||
br i1 false, label %deref.throw, label %deref.next3
|
||||
|
||||
deref.next6: ; preds = %deref.next4
|
||||
%9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
%10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
%11 = load float, float* %10, align 4
|
||||
%12 = load float, float* %9, align 4
|
||||
br i1 false, label %store.throw, label %store.next
|
||||
deref.next3: ; preds = %deref.next2
|
||||
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
|
||||
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
|
||||
%5 = load float, ptr %4, align 4
|
||||
%6 = load float, ptr %3, align 4
|
||||
br i1 false, label %deref.throw, label %store.next
|
||||
|
||||
store.next: ; preds = %deref.next6
|
||||
store float %8, float* %3, align 8
|
||||
br i1 false, label %store.throw7, label %store.next8
|
||||
store.next: ; preds = %deref.next3
|
||||
store float %2, ptr %complit, align 4
|
||||
br i1 false, label %deref.throw, label %store.next4
|
||||
|
||||
store.next8: ; preds = %store.next
|
||||
%13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
||||
%14 = fadd float %11, %12
|
||||
store float %14, float* %13, align 4
|
||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
%.unpack = load float, float* %.elt, align 8
|
||||
%15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
|
||||
%16 = insertvalue %"main.Point[float32]" %15, float %14, 1
|
||||
ret %"main.Point[float32]" %16
|
||||
store.next4: ; preds = %store.next
|
||||
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
|
||||
%8 = fadd float %5, %6
|
||||
store float %8, ptr %7, align 4
|
||||
%.unpack = load float, ptr %complit, align 4
|
||||
%9 = insertvalue %"main.Point[float32]" poison, float %.unpack, 0
|
||||
%10 = insertvalue %"main.Point[float32]" %9, float %8, 1
|
||||
ret %"main.Point[float32]" %10
|
||||
|
||||
deref.throw: ; preds = %entry
|
||||
unreachable
|
||||
|
||||
deref.throw1: ; preds = %deref.next
|
||||
unreachable
|
||||
|
||||
deref.throw3: ; preds = %deref.next2
|
||||
unreachable
|
||||
|
||||
deref.throw5: ; preds = %deref.next4
|
||||
unreachable
|
||||
|
||||
store.throw: ; preds = %deref.next6
|
||||
unreachable
|
||||
|
||||
store.throw7: ; preds = %store.next
|
||||
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @main.checkSize(i32, i8*) #0
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
|
||||
|
||||
declare void @runtime.nilPanic(i8*) #0
|
||||
declare void @main.checkSize(i32, ptr) #0
|
||||
|
||||
declare void @runtime.nilPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, i8* %context) unnamed_addr #1 {
|
||||
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%complit = alloca %"main.Point[int]", align 8
|
||||
%b = alloca %"main.Point[int]", align 8
|
||||
%a = alloca %"main.Point[int]", align 8
|
||||
%a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
store i32 0, i32* %a.repack, align 8
|
||||
%a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
store i32 0, i32* %a.repack9, align 4
|
||||
%0 = bitcast %"main.Point[int]"* %a to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
store i32 %a.X, i32* %a.repack10, align 8
|
||||
%a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
store i32 %a.Y, i32* %a.repack11, align 4
|
||||
%b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
store i32 0, i32* %b.repack, align 8
|
||||
%b.repack13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
store i32 0, i32* %b.repack13, align 4
|
||||
%1 = bitcast %"main.Point[int]"* %b to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%b.repack14 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
store i32 %b.X, i32* %b.repack14, align 8
|
||||
%b.repack15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
store i32 %b.Y, i32* %b.repack15, align 4
|
||||
call void @main.checkSize(i32 4, i8* undef) #2
|
||||
call void @main.checkSize(i32 8, i8* undef) #2
|
||||
%complit.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
store i32 0, i32* %complit.repack, align 8
|
||||
%complit.repack17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
||||
store i32 0, i32* %complit.repack17, align 4
|
||||
%2 = bitcast %"main.Point[int]"* %complit to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
||||
%3 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
%stackalloc = alloca i8, align 1
|
||||
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store i32 %a.X, ptr %a, align 4
|
||||
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4
|
||||
store i32 %a.Y, ptr %a.repack5, align 4
|
||||
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store i32 %b.X, ptr %b, align 4
|
||||
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4
|
||||
store i32 %b.Y, ptr %b.repack7, align 4
|
||||
call void @main.checkSize(i32 4, ptr undef) #3
|
||||
call void @main.checkSize(i32 8, ptr undef) #3
|
||||
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
|
||||
br i1 false, label %deref.throw, label %deref.next
|
||||
|
||||
deref.next: ; preds = %entry
|
||||
br i1 false, label %deref.throw1, label %deref.next2
|
||||
br i1 false, label %deref.throw, label %deref.next1
|
||||
|
||||
deref.next2: ; preds = %deref.next
|
||||
%4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
%5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
%6 = load i32, i32* %5, align 8
|
||||
%7 = load i32, i32* %4, align 8
|
||||
%8 = add i32 %6, %7
|
||||
br i1 false, label %deref.throw3, label %deref.next4
|
||||
deref.next1: ; preds = %deref.next
|
||||
%0 = load i32, ptr %a, align 4
|
||||
%1 = load i32, ptr %b, align 4
|
||||
%2 = add i32 %0, %1
|
||||
br i1 false, label %deref.throw, label %deref.next2
|
||||
|
||||
deref.next4: ; preds = %deref.next2
|
||||
br i1 false, label %deref.throw5, label %deref.next6
|
||||
deref.next2: ; preds = %deref.next1
|
||||
br i1 false, label %deref.throw, label %deref.next3
|
||||
|
||||
deref.next6: ; preds = %deref.next4
|
||||
%9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
%10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
%11 = load i32, i32* %10, align 4
|
||||
%12 = load i32, i32* %9, align 4
|
||||
br i1 false, label %store.throw, label %store.next
|
||||
deref.next3: ; preds = %deref.next2
|
||||
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
|
||||
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
|
||||
%5 = load i32, ptr %4, align 4
|
||||
%6 = load i32, ptr %3, align 4
|
||||
br i1 false, label %deref.throw, label %store.next
|
||||
|
||||
store.next: ; preds = %deref.next6
|
||||
store i32 %8, i32* %3, align 8
|
||||
br i1 false, label %store.throw7, label %store.next8
|
||||
store.next: ; preds = %deref.next3
|
||||
store i32 %2, ptr %complit, align 4
|
||||
br i1 false, label %deref.throw, label %store.next4
|
||||
|
||||
store.next8: ; preds = %store.next
|
||||
%13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
||||
%14 = add i32 %11, %12
|
||||
store i32 %14, i32* %13, align 4
|
||||
%.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
%.unpack = load i32, i32* %.elt, align 8
|
||||
%15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
|
||||
%16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
|
||||
ret %"main.Point[int]" %16
|
||||
store.next4: ; preds = %store.next
|
||||
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
|
||||
%8 = add i32 %5, %6
|
||||
store i32 %8, ptr %7, align 4
|
||||
%.unpack = load i32, ptr %complit, align 4
|
||||
%9 = insertvalue %"main.Point[int]" poison, i32 %.unpack, 0
|
||||
%10 = insertvalue %"main.Point[int]" %9, i32 %8, 1
|
||||
ret %"main.Point[int]" %10
|
||||
|
||||
deref.throw: ; preds = %entry
|
||||
unreachable
|
||||
|
||||
deref.throw1: ; preds = %deref.next
|
||||
unreachable
|
||||
|
||||
deref.throw3: ; preds = %deref.next2
|
||||
unreachable
|
||||
|
||||
deref.throw5: ; preds = %deref.next4
|
||||
unreachable
|
||||
|
||||
store.throw: ; preds = %deref.next6
|
||||
unreachable
|
||||
|
||||
store.throw7: ; preds = %store.next
|
||||
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry
|
||||
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 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+13
-17
@@ -5,27 +5,24 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
|
||||
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 #2 {
|
||||
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp slt i16 %len, 0
|
||||
@@ -39,25 +36,24 @@ unsafe.String.next: ; preds = %entry
|
||||
%5 = zext nneg i16 %len to i32
|
||||
%6 = insertvalue %runtime._string undef, ptr %ptr, 0
|
||||
%7 = insertvalue %runtime._string %6, i32 %5, 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret %runtime._string %7
|
||||
|
||||
unsafe.String.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.unsafeStringData(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %s.data
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+65
-63
@@ -5,32 +5,32 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.smin.i32(i32, i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
@@ -38,7 +38,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
@@ -47,91 +47,109 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i8 @llvm.umin.i8(i8, i8) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp olt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
ret float %1
|
||||
}
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umin.i32(i32, i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp olt double %a, %b
|
||||
%1 = select i1 %0, double %a, double %b
|
||||
ret double %1
|
||||
%0 = call float @llvm.minimum.f32(float %a, float %b)
|
||||
ret float %0
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare float @llvm.minimum.f32(float, float) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call double @llvm.minimum.f64(double %a, double %b)
|
||||
ret double %0
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare double @llvm.minimum.f64(double, double) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.minString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||
%stackalloc = alloca i8, align 1
|
||||
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
|
||||
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #4
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = select i1 %4, ptr %a.data, ptr %b.data
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.smax.i32(i32, i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
ret float %1
|
||||
}
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umax.i32(i32, i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call float @llvm.maximum.f32(float %a, float %b)
|
||||
ret float %0
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare float @llvm.maximum.f32(float, float) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.maxString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||
%stackalloc = alloca i8, align 1
|
||||
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
|
||||
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #4
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = select i1 %4, ptr %a.data, ptr %b.data
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = shl i32 %s.len, 2
|
||||
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
|
||||
@@ -142,38 +160,22 @@ entry:
|
||||
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearMap(ptr dereferenceable_or_null(48) %m, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
|
||||
call void @runtime.hashmapClear(ptr %m, ptr undef) #4
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(48), ptr) #0
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.smin.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i8 @llvm.umin.i8(i8, i8) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umin.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.smax.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umax.i32(i32, i32) #4
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
||||
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #5 = { nounwind }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
+63
-56
@@ -5,53 +5,50 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #0 {
|
||||
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 #0 {
|
||||
entry:
|
||||
%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
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #11
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, ptr) #2
|
||||
declare void @main.regularFunction(i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #2
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #1
|
||||
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
|
||||
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 #0 {
|
||||
entry:
|
||||
%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
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11
|
||||
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 #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
|
||||
@@ -59,25 +56,28 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
|
||||
store i32 3, ptr %n, align 4
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %n, ptr %1, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
|
||||
%2 = load i32, ptr %n, align 4
|
||||
call void @runtime.printlock(ptr undef) #9
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
||||
call void @runtime.printunlock(ptr undef) #9
|
||||
call void @runtime.printlock(ptr undef) #11
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #11
|
||||
call void @runtime.printunlock(ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
store i32 7, ptr %context, align 4
|
||||
ret void
|
||||
@@ -93,23 +93,23 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printlock(ptr) #2
|
||||
declare void @runtime.printlock(ptr) #1
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
declare void @runtime.printint32(i32, ptr) #1
|
||||
|
||||
declare void @runtime.printunlock(ptr) #2
|
||||
declare void @runtime.printunlock(ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
store ptr %fn.funcptr, ptr %2, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #11
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -121,38 +121,43 @@ entry:
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
call void %5(i32 %1, ptr %3) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #0 {
|
||||
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 #0 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
||||
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umin.i32(i32, i32) #7
|
||||
|
||||
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #2
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr @"main$string", ptr %1, align 4
|
||||
@@ -160,15 +165,15 @@ entry:
|
||||
store i32 4, ptr %2, align 4
|
||||
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||
store ptr %itf.typecode, ptr %3, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #11
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
|
||||
entry:
|
||||
%1 = load ptr, ptr %0, align 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
@@ -177,17 +182,19 @@ entry:
|
||||
%5 = load i32, ptr %4, align 4
|
||||
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||
%7 = load ptr, ptr %6, align 4
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #0 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #1 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #2 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #4 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
||||
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #9 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #10 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #11 = { nounwind }
|
||||
|
||||
+70
-63
@@ -5,85 +5,85 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, ptr) #1
|
||||
declare void @main.regularFunction(i32, ptr) #0
|
||||
|
||||
declare void @runtime.deadlock(ptr) #1
|
||||
declare void @runtime.deadlock(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
|
||||
call void @runtime.deadlock(ptr undef) #11
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint ptr %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #11
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
|
||||
store i32 3, ptr %n, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #11
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %n, ptr %1, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||
%2 = load i32, ptr %n, align 4
|
||||
call void @runtime.printlock(ptr undef) #9
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
||||
call void @runtime.printunlock(ptr undef) #9
|
||||
call void @runtime.printlock(ptr undef) #11
|
||||
call void @runtime.printint32(i32 %2, ptr undef) #11
|
||||
call void @runtime.printunlock(ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
store i32 7, ptr %context, align 4
|
||||
ret void
|
||||
@@ -96,28 +96,28 @@ entry:
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #11
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.printlock(ptr) #1
|
||||
declare void @runtime.printlock(ptr) #0
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #1
|
||||
declare void @runtime.printint32(i32, ptr) #0
|
||||
|
||||
declare void @runtime.printunlock(ptr) #1
|
||||
declare void @runtime.printunlock(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
store ptr %fn.funcptr, ptr %2, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -129,41 +129,46 @@ entry:
|
||||
%3 = load ptr, ptr %2, align 4
|
||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||
%5 = load ptr, ptr %4, align 4
|
||||
call void %5(i32 %1, ptr %3) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
call void %5(i32 %1, ptr %3) #11
|
||||
call void @runtime.deadlock(ptr undef) #11
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
||||
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umin.i32(i32, i32) #7
|
||||
|
||||
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
store ptr @"main$string", ptr %1, align 4
|
||||
@@ -171,14 +176,14 @@ entry:
|
||||
store i32 4, ptr %2, align 4
|
||||
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||
store ptr %itf.typecode, ptr %3, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #11
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #9
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #10 {
|
||||
entry:
|
||||
%1 = load ptr, ptr %0, align 4
|
||||
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||
@@ -187,18 +192,20 @@ entry:
|
||||
%5 = load i32, ptr %4, align 4
|
||||
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||
%7 = load ptr, ptr %6, align 4
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
|
||||
call void @runtime.deadlock(ptr undef) #9
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #11
|
||||
call void @runtime.deadlock(ptr undef) #11
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #4 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #8 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #9 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #10 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #11 = { nounwind }
|
||||
|
||||
Vendored
+42
-44
@@ -9,65 +9,64 @@ target triple = "wasm32-unknown-wasi"
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.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.signature:Error:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, { i32, [1 x ptr] }, [7 x i8] } { i8 116, i16 -32767, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type.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:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] } }, align 4
|
||||
@"reflect/types.type: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.signature:String:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
|
||||
@"reflect/types.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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
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
|
||||
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
|
||||
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
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
|
||||
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
|
||||
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 #2 {
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
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
|
||||
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
|
||||
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 #2 {
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 {
|
||||
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) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
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
|
||||
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 #2 {
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #6
|
||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -77,12 +76,12 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -92,12 +91,12 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -107,34 +106,33 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
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) #7
|
||||
%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
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
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) #7
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #6
|
||||
%1 = extractvalue %runtime._string %0, 0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #6
|
||||
ret %runtime._string %0
|
||||
}
|
||||
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #5
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #7 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #6 = { nounwind }
|
||||
|
||||
Vendored
+12
-16
@@ -3,48 +3,44 @@ source_filename = "pointer.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||
target 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret [0 x i32] zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+33
@@ -115,3 +115,36 @@ func doesNotEscapeParam(a *int, b []int, c chan int, d *[0]byte)
|
||||
//go:noescape
|
||||
func stillEscapes(a *int, b []int, c chan int, d *[0]byte) {
|
||||
}
|
||||
|
||||
//go:noheap
|
||||
func doesHeapAlloc() *int {
|
||||
return new(int)
|
||||
}
|
||||
|
||||
// Define a function in a different package using a file-level go:linkname.
|
||||
// (Same as withLinkageName1, but with the //go:linkname directive detached
|
||||
// from the function declaration — see https://github.com/tinygo-org/tinygo/issues/4395)
|
||||
func withFileLevelLinkageName1() {
|
||||
}
|
||||
|
||||
// Import a function from a different package using a file-level go:linkname.
|
||||
// (Same as withLinkageName2, but with the //go:linkname directive detached
|
||||
// from the function declaration.)
|
||||
func withFileLevelLinkageName2()
|
||||
|
||||
//go:linkname withFileLevelLinkageName1 somepkg.someFileLevelFunction1
|
||||
//go:linkname withFileLevelLinkageName2 somepkg.someFileLevelFunction2
|
||||
|
||||
// File-level linkname directives can also appear between two function
|
||||
// declarations, in which case Go's AST attaches them as the doc comment
|
||||
// of the following function — even when the directive's localname refers
|
||||
// to a different function. Exercise that case: the directive below names
|
||||
// withAdjacentLinkageName, but Go will attach it to
|
||||
// sentinelAfterAdjacentLinkname's Doc. The file-level scan must find it
|
||||
// by walking comment groups regardless of which decl they're attached to.
|
||||
func withAdjacentLinkageName() {
|
||||
}
|
||||
|
||||
//go:linkname withAdjacentLinkageName somepkg.someAdjacentFunction
|
||||
func sentinelAfterAdjacentLinkname() {
|
||||
}
|
||||
|
||||
Vendored
+60
-30
@@ -11,95 +11,125 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @extern_func() #3 {
|
||||
define void @extern_func() #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @somepkg.someFunction2(ptr) #1
|
||||
declare void @somepkg.someFunction2(ptr) #0
|
||||
|
||||
; Function Attrs: inlinehint nounwind
|
||||
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
|
||||
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #3 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #5 {
|
||||
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #4 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.useGeneric(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.useGeneric(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"main.noinlineGenericFunc[int8]"(ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #5 {
|
||||
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #4 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
|
||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #4 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define void @exportedFunctionInSection() #6 section ".special_function_section" {
|
||||
define void @exportedFunctionInSection() #5 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.declaredImport() #7
|
||||
declare void @main.declaredImport() #6
|
||||
|
||||
declare void @imported() #8
|
||||
declare void @imported() #7
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @exported() #9 {
|
||||
define void @exported() #8 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #0
|
||||
|
||||
declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #1
|
||||
declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.stillEscapes(ptr dereferenceable_or_null(4) %a, ptr %b.data, i32 %b.len, i32 %b.cap, ptr dereferenceable_or_null(36) %c, ptr %d, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.stillEscapes(ptr dereferenceable_or_null(4) %a, ptr %b.data, i32 %b.len, i32 %b.cap, ptr dereferenceable_or_null(36) %c, ptr %d, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.doesHeapAlloc(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 4 dereferenceable(4) ptr @runtime.alloc_noheap(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #10
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #10
|
||||
ret ptr %new
|
||||
}
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc_noheap(i32, ptr, ptr) #9
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someFileLevelFunction1(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @somepkg.someFileLevelFunction2(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someAdjacentFunction(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.sentinelAfterAdjacentLinkname(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
|
||||
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
|
||||
attributes #9 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #10 = { nounwind }
|
||||
|
||||
Vendored
+74
-66
@@ -3,31 +3,28 @@ source_filename = "slice.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
|
||||
target 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
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 #2 {
|
||||
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %ints.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -38,84 +35,93 @@ lookup.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
call void @runtime.lookupPanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
declare void @runtime.lookupPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #5
|
||||
store i32 1, ptr %varargs, align 4
|
||||
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4
|
||||
store i32 2, ptr %0, align 4
|
||||
%1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8
|
||||
store i32 3, ptr %1, align 4
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %4
|
||||
}
|
||||
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
|
||||
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
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 #2 {
|
||||
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
|
||||
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
|
||||
%copy.size = shl nuw i32 %copy.n, 2
|
||||
call void @llvm.memmove.p0.p0.i32(ptr align 4 %dst.data, ptr align 4 %src.data, i32 %copy.size, i1 false)
|
||||
ret i32 %copy.n
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umin.i32(i32, i32) #3
|
||||
|
||||
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
call void @runtime.slicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.slicePanic(ptr) #1
|
||||
declare void @runtime.slicePanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
@@ -123,20 +129,20 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl nuw i32 %len, 1
|
||||
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
call void @runtime.slicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
||||
@@ -144,20 +150,20 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = mul i32 %len, 3
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
call void @runtime.slicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
||||
@@ -165,39 +171,39 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl nuw i32 %len, 2
|
||||
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%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) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(ptr undef) #3
|
||||
call void @runtime.slicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = getelementptr i8, ptr %p, i32 %len
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
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) #3
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret ptr %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp ult i32 %s.len, 4
|
||||
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
||||
@@ -206,18 +212,18 @@ slicetoarray.next: ; preds = %entry
|
||||
ret ptr %s.data
|
||||
|
||||
slicetoarray.throw: ; preds = %entry
|
||||
call void @runtime.sliceToArrayPointerPanic(ptr undef) #3
|
||||
call void @runtime.sliceToArrayPointerPanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #1
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #5
|
||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
slicetoarray.next: ; preds = %entry
|
||||
@@ -228,7 +234,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 #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i32 %len, 1073741823
|
||||
@@ -242,18 +248,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) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %7
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp eq ptr %ptr, null
|
||||
@@ -266,16 +272,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) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %6
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -290,16 +296,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) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -314,15 +320,17 @@ 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) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #3
|
||||
call void @runtime.unsafeSlicePanic(ptr undef) #5
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
Vendored
+21
-25
@@ -7,37 +7,34 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret %runtime._string { ptr @"main$string", i32 3 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret %runtime._string zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.stringLen(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %s.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.stringIndex(ptr readonly %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -48,40 +45,40 @@ lookup.next: ; preds = %entry
|
||||
ret i8 %1
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
call void @runtime.lookupPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
declare void @runtime.lookupPanic(ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.stringCompareEqual(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.stringCompareUnequal(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
|
||||
%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 #2 {
|
||||
define hidden i1 @main.stringCompareLarger(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #2
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.stringLookup(ptr readonly %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = zext i8 %x to i32
|
||||
%.not = icmp ugt i32 %s.len, %0
|
||||
@@ -93,11 +90,10 @@ lookup.next: ; preds = %entry
|
||||
ret i8 %2
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(ptr undef) #3
|
||||
call void @runtime.lookupPanic(ptr undef) #2
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+24
-54
@@ -5,19 +5,16 @@ 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) #1
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
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 #3 {
|
||||
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -27,29 +24,23 @@ entry:
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
|
||||
%5 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
|
||||
%3 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
%6 = load i32, ptr %hashmap.value, align 4
|
||||
%4 = load i32, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
ret i32 %6
|
||||
ret i32 %4
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
declare void @runtime.memzero(ptr, i32, ptr) #1
|
||||
|
||||
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.hashmapGenericGet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, i32, ptr) #0
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
; 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 #3 {
|
||||
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -60,20 +51,16 @@ entry:
|
||||
store i32 5, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
|
||||
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
|
||||
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) #1
|
||||
declare void @runtime.hashmapGenericSet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, ptr) #0
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -84,23 +71,15 @@ entry:
|
||||
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
|
||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 21
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
|
||||
%0 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4
|
||||
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
%5 = load i32, ptr %hashmap.value, align 4
|
||||
%1 = load i32, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
ret i32 %5
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -112,29 +91,20 @@ entry:
|
||||
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
|
||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
|
||||
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
|
||||
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
|
||||
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
|
||||
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
|
||||
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 21
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
|
||||
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4
|
||||
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 #2 {
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #5 = { nounwind }
|
||||
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
@@ -59,7 +59,6 @@ func TestCorpus(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, repo := range repos {
|
||||
repo := repo
|
||||
name := repo.Repo
|
||||
if repo.Tags != "" {
|
||||
name += "(" + strings.ReplaceAll(repo.Tags, " ", "-") + ")"
|
||||
@@ -132,7 +131,6 @@ func TestCorpus(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, dir := range repo.Subdirs {
|
||||
dir := dir
|
||||
t.Run(dir.Pkg, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -116,10 +116,7 @@ func Diff(oldName string, old []byte, newName string, new []byte) []byte {
|
||||
|
||||
// End chunk with common lines for context.
|
||||
if len(ctext) > 0 {
|
||||
n := end.x - start.x
|
||||
if n > C {
|
||||
n = C
|
||||
}
|
||||
n := min(end.x-start.x, C)
|
||||
for _, s := range x[start.x : start.x+n] {
|
||||
ctext = append(ctext, " "+s)
|
||||
count.x++
|
||||
@@ -234,7 +231,7 @@ func tgs(x, y []string) []pair {
|
||||
for i := range T {
|
||||
T[i] = n + 1
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
k := sort.Search(n, func(k int) bool {
|
||||
return T[k] >= J[i]
|
||||
})
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ func TestErrors(t *testing.T) {
|
||||
{name: "loader-invaliddep"},
|
||||
{name: "loader-invalidpackage"},
|
||||
{name: "loader-nopackage"},
|
||||
{name: "noheap", target: "cortex-m-qemu"},
|
||||
{name: "optimizer"},
|
||||
{name: "syntax"},
|
||||
{name: "types"},
|
||||
@@ -135,7 +136,7 @@ func readErrorMessages(t *testing.T, file string) string {
|
||||
}
|
||||
|
||||
var errors []string
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
for line := range strings.SplitSeq(string(data), "\n") {
|
||||
if strings.HasPrefix(line, "// ERROR: ") {
|
||||
errors = append(errors, strings.TrimRight(line[len("// ERROR: "):], "\r\n"))
|
||||
}
|
||||
|
||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1747953325,
|
||||
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
|
||||
"lastModified": 1770136044,
|
||||
"narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
|
||||
"rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-25.05",
|
||||
"ref": "nixos-25.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
inputs = {
|
||||
# Use a recent stable release, but fix the version to make it reproducible.
|
||||
# This version should be updated from time to time.
|
||||
nixpkgs.url = "nixpkgs/nixos-25.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-25.11";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
|
||||
@@ -1,29 +1,53 @@
|
||||
module github.com/tinygo-org/tinygo
|
||||
|
||||
go 1.22.0
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/golangci/misspell v0.6.0
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/mgechev/revive v1.3.9
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
github.com/tetratelabs/wazero v1.6.0
|
||||
go.bug.st/serial v1.6.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/tools v0.30.0
|
||||
github.com/tetratelabs/wazero v1.9.0
|
||||
go.bug.st/serial v1.6.4
|
||||
go.bytecodealliance.org v0.6.2
|
||||
go.bytecodealliance.org/cm v0.2.2
|
||||
golang.org/x/net v0.50.0
|
||||
golang.org/x/sys v0.41.0
|
||||
golang.org/x/tools v0.42.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74
|
||||
tinygo.org/x/espflasher v0.6.1
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/regclient/regclient v0.8.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
|
||||
golang.org/x/mod v0.33.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@@ -23,40 +44,83 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
|
||||
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
|
||||
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
|
||||
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
|
||||
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
|
||||
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
|
||||
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
|
||||
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
|
||||
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
|
||||
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74 h1:ovavgTdIBWCH8YWlcfq9gkpoyT1+IxMKSn+Df27QwE8=
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
tinygo.org/x/espflasher v0.6.1 h1:9jfyAP9jGjxF63FQUY2Bml9TFb5fCZYxVgbgR2IjUGs=
|
||||
tinygo.org/x/espflasher v0.6.1/go.mod h1:tr5u08HoE67WD5zxJesCiiVF/R1b6Akz3yXwh5zah8U=
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6 h1:QSnqFgNV2Ij0T4hM2qKv53fcDAFElxClPjVUZXzYkWU=
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
@@ -151,6 +151,8 @@ func Get(name string) string {
|
||||
panic("could not find cache dir: " + err.Error())
|
||||
}
|
||||
return filepath.Join(dir, "tinygo")
|
||||
case "CGO_CFLAGS":
|
||||
return os.Getenv("CGO_CFLAGS")
|
||||
case "CGO_ENABLED":
|
||||
// Always enable CGo. It is required by a number of targets, including
|
||||
// macOS and the rp2040.
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.40.0-dev"
|
||||
const version = "0.42.0-dev"
|
||||
|
||||
// Return TinyGo version, either in the form 0.30.0 or as a development version
|
||||
// (like 0.30.0-dev-abcd012).
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// TODO: remove this (by merging it into the top-level go.mod)
|
||||
// once the top level go.mod specifies a go new enough to make our version of misspell happy.
|
||||
|
||||
module tools
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/golangci/misspell v0.6.0
|
||||
github.com/mgechev/revive v1.3.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
)
|
||||
@@ -1,56 +0,0 @@
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
|
||||
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,5 +0,0 @@
|
||||
# wasm-tools directory
|
||||
|
||||
This directory has a separate `go.mod` file because the `wasm-tools-go` module requires Go 1.22, while TinyGo itself supports Go 1.19.
|
||||
|
||||
When the minimum Go version for TinyGo is 1.22, this directory can be folded into `internal/tools` and the `go.mod` and `go.sum` files deleted.
|
||||
@@ -1,22 +0,0 @@
|
||||
module github.com/tinygo-org/tinygo/internal/wasm-tools
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
go.bytecodealliance.org v0.6.2
|
||||
go.bytecodealliance.org/cm v0.2.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/regclient/regclient v0.8.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
@@ -1,48 +0,0 @@
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
|
||||
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
|
||||
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
|
||||
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
|
||||
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
|
||||
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
|
||||
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,12 +0,0 @@
|
||||
//go:build tools
|
||||
|
||||
// Install tools specified in go.mod.
|
||||
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "go.bytecodealliance.org/cm"
|
||||
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
|
||||
)
|
||||
|
||||
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
|
||||
+1
-1
@@ -151,7 +151,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
|
||||
case llvm.PHI:
|
||||
inst.name = llvmInst.Name()
|
||||
incomingCount := inst.llvmInst.IncomingCount()
|
||||
for i := 0; i < incomingCount; i++ {
|
||||
for i := range incomingCount {
|
||||
incomingBB := inst.llvmInst.IncomingBlock(i)
|
||||
incomingValue := inst.llvmInst.IncomingValue(i)
|
||||
inst.operands = append(inst.operands,
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ var (
|
||||
errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
|
||||
errMapAlreadyCreated = errors.New("interp: map already created")
|
||||
errLoopUnrolled = errors.New("interp: loop unrolled")
|
||||
errLoopTooLong = errors.New("interp: loop ran too many iterations")
|
||||
)
|
||||
|
||||
// This is one of the errors that can be returned from toLLVMValue when the
|
||||
@@ -29,7 +30,7 @@ var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not
|
||||
func isRecoverableError(err error) bool {
|
||||
return err == errIntegerAsPointer || err == errUnsupportedInst ||
|
||||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
|
||||
err == errLoopUnrolled
|
||||
err == errLoopUnrolled || err == errLoopTooLong || err == errInvalidPtrToIntSize
|
||||
}
|
||||
|
||||
// ErrorLine is one line in a traceback. The position may be missing.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user