mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
Compare commits
238 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb6edeae80 | |||
| 4517a0c17b | |||
| 6abaee4640 | |||
| 1270a50104 | |||
| 868262f4a7 | |||
| d33ace7b59 | |||
| dd6fa89aa6 | |||
| d513cae5d2 | |||
| e612f7cf3f | |||
| 385a7920e6 | |||
| 077b35e9ad | |||
| 880e940417 | |||
| ad6c89bf64 | |||
| ae6220262a | |||
| e731a31eb9 | |||
| 3023ba584b | |||
| 3a8ef33c72 | |||
| 20b58a0128 | |||
| bfccf3592a | |||
| 272fea13e7 | |||
| b6fd0c818e | |||
| c383a407e3 | |||
| 7b7601d77c | |||
| f7c0466f78 | |||
| 81ce7fb738 | |||
| c2776dcf78 | |||
| ad0340d437 | |||
| 30c4df16f2 | |||
| fe27b674cd | |||
| c78dbcd3f2 | |||
| 8890b57ba0 | |||
| ee3a05f1de | |||
| 9307204111 | |||
| 71878c2c0c | |||
| cef2a82c97 | |||
| 1d9f26cee1 | |||
| 6e58c44390 | |||
| 7d6b667bba | |||
| 72f30ca6ec | |||
| 293b620faf | |||
| ad0af607ef | |||
| da23cdeae4 | |||
| d419cc11bf | |||
| 441dfc98d7 | |||
| 2b3b870bfe | |||
| 7748c4922e | |||
| 50f700ddb5 | |||
| f986ea84ac | |||
| 797a5a2031 | |||
| 3d433fe9f1 | |||
| 1154212c15 | |||
| 22bf045c9a | |||
| 39029cc376 | |||
| 7122755725 | |||
| dcee228c4e | |||
| 9d6e30701b | |||
| 85b59e66da | |||
| 90b0bf646c | |||
| c55ac9f28e | |||
| 2733e376bd | |||
| 331cfb65b7 | |||
| 055950421a | |||
| cfcc894855 | |||
| 8bd0155c51 | |||
| 32a056c32a | |||
| 8e8ad9004f | |||
| 62d8cdb218 | |||
| b6fdbee14e | |||
| a5ceb793be | |||
| 7c546525ea | |||
| d628e3e2cb | |||
| d97e4dbccf | |||
| a7ddb33bea | |||
| 8a93196f1f | |||
| 6714974aba | |||
| d67ec3b266 | |||
| 78775007fa | |||
| ad4d722f54 | |||
| 6384ecace0 | |||
| 38881a2850 | |||
| 0f1cf14743 | |||
| 7c34f7704e | |||
| 377415a6c3 | |||
| 1e13c6d18f | |||
| 14121f4b0e | |||
| 7768195835 | |||
| c095b7e9c4 | |||
| 1f6d34d995 | |||
| 9951eb9990 | |||
| c8f77d26a8 | |||
| 8eaa9bd8d0 | |||
| 6061f3db92 | |||
| 410aa0e0d8 | |||
| c66836cf3a | |||
| ca9211b582 | |||
| cb7d470ba4 | |||
| 5baee9a8ee | |||
| c47f52b546 | |||
| a2588d8db3 | |||
| f529b6071d | |||
| 5557e97888 | |||
| d04b07fa8b | |||
| 7486277012 | |||
| 36d60b8349 | |||
| c55191283b | |||
| ad30085b93 | |||
| e9ca41735a | |||
| df1f83f4e1 | |||
| 5879d785a9 | |||
| 186018abeb | |||
| 828b9614c2 | |||
| f5e933cd4d | |||
| 0952b1b984 | |||
| ed55f56d85 | |||
| edb8766aab | |||
| 413bb55e2c | |||
| 0db1a4bec1 | |||
| 2867da164d | |||
| 7b8ae2d6b6 | |||
| 5b8127fd4e | |||
| cc3e785692 | |||
| 0ea5cfc8fe | |||
| 70f1a5429a | |||
| 2fb2113168 | |||
| cb39611389 | |||
| 45764325b4 | |||
| bb66232164 | |||
| 9679e7f1cc | |||
| 6cdfc298cf | |||
| 9a4bfd0e96 | |||
| ee3106be98 | |||
| 57f49af726 | |||
| 38a80b45d3 | |||
| e9003e2deb | |||
| 204659bdcd | |||
| 08ca1d13d0 | |||
| 53db436a7d | |||
| 0ad15551c8 | |||
| afd65e224a | |||
| 5f50c3b60b | |||
| 8858d49989 | |||
| cf39d8b2c8 | |||
| d92a31b440 | |||
| 9c77a38358 | |||
| d0445d6f83 | |||
| a40b11f535 | |||
| 8c90f4facf | |||
| c7c9a76af5 | |||
| 6984af43a0 | |||
| 81c56c3ab8 | |||
| 3d9a1ca22a | |||
| c2083014b3 | |||
| 603a81f194 | |||
| cfc32794a7 | |||
| 1d9c53d00e | |||
| 8d2a07b927 | |||
| ffe6dfd21b | |||
| cf21380264 | |||
| 534b3b0c0b | |||
| ceeb233ff6 | |||
| de3f0af829 | |||
| a511f18c64 | |||
| 731bd5cd1b | |||
| 4acf59546e | |||
| 2ee4d9aaa1 | |||
| b58b7c59ae | |||
| e14b6a7009 | |||
| a1a2d1ab81 | |||
| 07591178cd | |||
| 43bdc888dd | |||
| 4229e670ce | |||
| 76a7ad2a3e | |||
| e4f551ac7f | |||
| 338590cc75 | |||
| 22d70604d8 | |||
| c6add1e769 | |||
| c6609a02fa | |||
| a449c4813a | |||
| 19fb1bfafc | |||
| f91b6ad0df | |||
| 94459cefe5 | |||
| 803ba4f54d | |||
| 2919fa8b14 | |||
| 6420e90124 | |||
| 2d289addb7 | |||
| 4df145dcb4 | |||
| e065da20cb | |||
| d7c77b6761 | |||
| f51029484a | |||
| 03cfcbc17c | |||
| 649f49e000 | |||
| 3bcd4dc3e0 | |||
| 772c71ec27 | |||
| 9b896dc981 | |||
| d4189feca6 | |||
| 777048cfa9 | |||
| 2b215955ca | |||
| ce25f00769 | |||
| 1a59aecb63 | |||
| cca32e67a9 | |||
| 174d492355 | |||
| 5355473dce | |||
| a531ed614a | |||
| 24ae6fdf29 | |||
| 938ce22307 | |||
| 9fb5a5b9a4 | |||
| 9fd9d9c05a | |||
| fd50227a3d | |||
| a90295430c | |||
| fa4ca63ff2 | |||
| 7019c4e8fc | |||
| b79e0e8528 | |||
| 51bed3afae | |||
| 4d4ccddad8 | |||
| f55f5315cc | |||
| 7468a00ef4 | |||
| 8d77278c6b | |||
| dde9b5ad3a | |||
| 2d4307647e | |||
| 935a293106 | |||
| 72b715fa99 | |||
| d801d0cd53 | |||
| c2f1965e03 | |||
| 75bba42b60 | |||
| 18b50db0dc | |||
| 499fce9cee | |||
| 88b29589d6 | |||
| 8cbfbcae5a | |||
| 5cd8ba2421 | |||
| 2320b18953 | |||
| 3b1913ac57 | |||
| 1da1abe314 | |||
| c9721197d5 | |||
| 738747bd05 | |||
| 0bb4a8abeb | |||
| 6ef8fcd537 | |||
| a896f7f218 | |||
| 081d2e58c6 |
+24
-15
@@ -10,12 +10,12 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-16-v3
|
- llvm-source-18-v1
|
||||||
- run:
|
- run:
|
||||||
name: "Fetch LLVM source"
|
name: "Fetch LLVM source"
|
||||||
command: make llvm-source
|
command: make llvm-source
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-source-16-v3
|
key: llvm-source-18-v1
|
||||||
paths:
|
paths:
|
||||||
- llvm-project/clang/lib/Headers
|
- llvm-project/clang/lib/Headers
|
||||||
- llvm-project/clang/include
|
- llvm-project/clang/include
|
||||||
@@ -33,13 +33,13 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- binaryen-linux-v2
|
- binaryen-linux-v3
|
||||||
- run:
|
- run:
|
||||||
name: "Build Binaryen"
|
name: "Build Binaryen"
|
||||||
command: |
|
command: |
|
||||||
make binaryen
|
make binaryen
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: binaryen-linux-v2
|
key: binaryen-linux-v3
|
||||||
paths:
|
paths:
|
||||||
- build/wasm-opt
|
- build/wasm-opt
|
||||||
test-linux:
|
test-linux:
|
||||||
@@ -55,7 +55,7 @@ commands:
|
|||||||
- run:
|
- run:
|
||||||
name: "Install apt dependencies"
|
name: "Install apt dependencies"
|
||||||
command: |
|
command: |
|
||||||
echo 'deb https://apt.llvm.org/buster/ llvm-toolchain-buster-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
|
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 -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
@@ -69,16 +69,16 @@ commands:
|
|||||||
- build-binaryen-linux
|
- build-binaryen-linux
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- go-cache-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||||
- go-cache-v3-{{ checksum "go.mod" }}
|
- go-cache-v4-{{ checksum "go.mod" }}
|
||||||
- llvm-source-linux
|
- llvm-source-linux
|
||||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- wasi-libc-sysroot-systemclang-v6
|
- wasi-libc-sysroot-systemclang-v7
|
||||||
- run: make wasi-libc
|
- run: make wasi-libc
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: wasi-libc-sysroot-systemclang-v6
|
key: wasi-libc-sysroot-systemclang-v7
|
||||||
paths:
|
paths:
|
||||||
- lib/wasi-libc/sysroot
|
- lib/wasi-libc/sysroot
|
||||||
- when:
|
- when:
|
||||||
@@ -88,22 +88,29 @@ commands:
|
|||||||
# Do this before gen-device so that it doesn't check the
|
# Do this before gen-device so that it doesn't check the
|
||||||
# formatting of generated files.
|
# formatting of generated files.
|
||||||
name: Check Go code formatting
|
name: Check Go code formatting
|
||||||
command: make fmt-check
|
command: make fmt-check lint
|
||||||
- run: make gen-device -j4
|
- run: make gen-device -j4
|
||||||
- run: make smoketest XTENSA=0
|
- run: make smoketest XTENSA=0
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: go-cache-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/go-build
|
- ~/.cache/go-build
|
||||||
- /go/pkg/mod
|
- /go/pkg/mod
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-llvm14-go118:
|
test-llvm15-go119:
|
||||||
docker:
|
docker:
|
||||||
- image: golang:1.18-buster
|
- image: golang:1.19-bullseye
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "14"
|
llvm: "15"
|
||||||
|
resource_class: large
|
||||||
|
test-llvm18-go122:
|
||||||
|
docker:
|
||||||
|
- image: golang:1.22-bullseye
|
||||||
|
steps:
|
||||||
|
- test-linux:
|
||||||
|
llvm: "18"
|
||||||
resource_class: large
|
resource_class: large
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
@@ -111,4 +118,6 @@ workflows:
|
|||||||
jobs:
|
jobs:
|
||||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||||
# least the smoke tests still pass.
|
# least the smoke tests still pass.
|
||||||
- test-llvm14-go118
|
- test-llvm15-go119
|
||||||
|
# This tests LLVM 18 support when linking against system libraries.
|
||||||
|
- test-llvm18-go122
|
||||||
|
|||||||
@@ -14,26 +14,36 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
build-macos:
|
build-macos:
|
||||||
name: build-macos
|
name: build-macos
|
||||||
runs-on: macos-11
|
strategy:
|
||||||
|
matrix:
|
||||||
|
# macos-12: amd64 (oldest supported version as of 05-02-2024)
|
||||||
|
# macos-14: arm64 (oldest arm64 version)
|
||||||
|
os: [macos-12, macos-14]
|
||||||
|
include:
|
||||||
|
- os: macos-12
|
||||||
|
goarch: amd64
|
||||||
|
- os: macos-14
|
||||||
|
goarch: arm64
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-macos-v1
|
key: llvm-source-18-${{ matrix.os }}-v2
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -44,7 +54,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -55,10 +65,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-macos-v1
|
key: llvm-build-18-${{ matrix.os }}-v2
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -73,16 +83,16 @@ jobs:
|
|||||||
make llvm-build
|
make llvm-build
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-${{ matrix.os }}-v1
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -98,7 +108,7 @@ jobs:
|
|||||||
run: make tinygo-test
|
run: make tinygo-test
|
||||||
- name: Make release artifact
|
- name: Make release artifact
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cp -p build/release.tar.gz build/tinygo.darwin-amd64.tar.gz
|
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
# Note: this release artifact is double-zipped, see:
|
# Note: this release artifact is double-zipped, see:
|
||||||
# https://github.com/actions/upload-artifact/issues/39
|
# https://github.com/actions/upload-artifact/issues/39
|
||||||
@@ -106,29 +116,44 @@ jobs:
|
|||||||
# - have a double-zipped artifact when downloaded from the UI
|
# - have a double-zipped artifact when downloaded from the UI
|
||||||
# - have a very slow artifact upload
|
# - have a very slow artifact upload
|
||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: darwin-amd64-double-zipped
|
name: darwin-${{ matrix.goarch }}-double-zipped
|
||||||
path: build/tinygo.darwin-amd64.tar.gz
|
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||||
- name: Smoke tests
|
- name: Smoke tests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||||
test-macos-homebrew:
|
test-macos-homebrew:
|
||||||
name: homebrew-install
|
name: homebrew-install
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
version: [16, 17, 18]
|
||||||
steps:
|
steps:
|
||||||
- name: Install LLVM
|
- name: Set up Homebrew
|
||||||
shell: bash
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
|
- name: Fix Python symlinks
|
||||||
run: |
|
run: |
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@16
|
# Github runners have broken symlinks, so relink
|
||||||
|
# see: https://github.com/actions/setup-python/issues/577
|
||||||
|
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||||
|
- name: Install LLVM
|
||||||
|
run: |
|
||||||
|
brew install llvm@${{ matrix.version }}
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Build TinyGo
|
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||||
run: go install
|
run: go install -tags=llvm${{ matrix.version }}
|
||||||
- name: Check binary
|
- name: Check binary
|
||||||
run: tinygo version
|
run: tinygo version
|
||||||
|
- name: Build TinyGo (default LLVM)
|
||||||
|
if: matrix.version == 18
|
||||||
|
run: go install
|
||||||
|
- name: Check binary
|
||||||
|
if: matrix.version == 18
|
||||||
|
run: tinygo version
|
||||||
|
|||||||
@@ -19,15 +19,26 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
|
- name: Free Disk space
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
|
sudo rm -rf /opt/hostedtoolcache
|
||||||
|
sudo rm -rf /usr/local/lib/android
|
||||||
|
sudo rm -rf /usr/share/dotnet
|
||||||
|
sudo rm -rf /opt/ghc
|
||||||
|
sudo rm -rf /usr/local/graalvm
|
||||||
|
sudo rm -rf /usr/local/share/boost
|
||||||
|
df -h
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
tinygo/tinygo-dev
|
tinygo/tinygo-dev
|
||||||
@@ -36,24 +47,23 @@ jobs:
|
|||||||
type=sha,format=long
|
type=sha,format=long
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
- name: Log in to Github Container Registry
|
- name: Log in to Github Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
build-contexts: tinygo-llvm-build=docker-image://tinygo/llvm-16
|
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
- name: Trigger Drivers repo build on Github Actions
|
- name: Trigger Drivers repo build on Github Actions
|
||||||
|
|||||||
+75
-177
@@ -18,32 +18,32 @@ jobs:
|
|||||||
# statically linked binary.
|
# statically linked binary.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: golang:1.21-alpine
|
image: golang:1.22-alpine
|
||||||
steps:
|
steps:
|
||||||
- name: Install apk dependencies
|
- name: Install apk dependencies
|
||||||
# tar: needed for actions/cache@v3
|
# tar: needed for actions/cache@v4
|
||||||
# git+openssh: needed for checkout (I think?)
|
# git+openssh: needed for checkout (I think?)
|
||||||
# ruby: needed to install fpm
|
# ruby: needed to install fpm
|
||||||
run: apk add tar git openssh make g++ ruby
|
run: apk add tar git openssh make g++ ruby-dev
|
||||||
- name: Work around CVE-2022-24765
|
- name: Work around CVE-2022-24765
|
||||||
# We're not on a multi-user machine, so this is safe.
|
# We're not on a multi-user machine, so this is safe.
|
||||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Cache Go
|
- name: Cache Go
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-alpine-v1
|
key: llvm-source-18-linux-alpine-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -65,10 +65,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-alpine-v1
|
key: llvm-build-18-linux-alpine-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -83,13 +83,13 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-alpine-v1
|
key: binaryen-linux-alpine-v1
|
||||||
@@ -100,10 +100,10 @@ jobs:
|
|||||||
apk add cmake samurai python3
|
apk add cmake samurai python3
|
||||||
make binaryen STATIC=1
|
make binaryen STATIC=1
|
||||||
- name: Cache wasi-libc
|
- name: Cache wasi-libc
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-alpine-v1
|
key: wasi-libc-sysroot-linux-alpine-v2
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -113,13 +113,15 @@ jobs:
|
|||||||
gem install --version 4.0.7 public_suffix
|
gem install --version 4.0.7 public_suffix
|
||||||
gem install --version 2.7.6 dotenv
|
gem install --version 2.7.6 dotenv
|
||||||
gem install --no-document fpm
|
gem install --no-document fpm
|
||||||
|
- name: Run linter
|
||||||
|
run: make lint
|
||||||
- name: Build TinyGo release
|
- name: Build TinyGo release
|
||||||
run: |
|
run: |
|
||||||
make release deb -j3 STATIC=1
|
make release deb -j3 STATIC=1
|
||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||||
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
path: |
|
path: |
|
||||||
@@ -131,20 +133,20 @@ jobs:
|
|||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||||
curl https://github.com/bytecodealliance/wasmtime/releases/download/v5.0.0/wasmtime-v5.0.0-x86_64-linux.tar.xz -o wasmtime-v5.0.0-x86_64-linux.tar.xz -SfL
|
curl https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
|
||||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v5.0.0-x86_64-linux.tar.xz --strip-components=1 wasmtime-v5.0.0-x86_64-linux/*
|
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
- name: Download release artifact
|
- name: Download release artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
- name: Extract release tarball
|
- name: Extract release tarball
|
||||||
@@ -161,7 +163,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
@@ -176,25 +178,25 @@ jobs:
|
|||||||
simavr \
|
simavr \
|
||||||
ninja-build
|
ninja-build
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '18'
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||||
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v5.0.0/wasmtime-v5.0.0-x86_64-linux.tar.xz -o wasmtime-v5.0.0-x86_64-linux.tar.xz -SfL
|
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
|
||||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v5.0.0-x86_64-linux.tar.xz --strip-components=1 wasmtime-v5.0.0-x86_64-linux/*
|
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-asserts-v1
|
key: llvm-source-18-linux-asserts-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -205,7 +207,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -216,10 +218,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-asserts-v1
|
key: llvm-build-18-linux-asserts-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -232,13 +234,13 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-asserts-v1
|
key: binaryen-linux-asserts-v1
|
||||||
@@ -247,10 +249,10 @@ jobs:
|
|||||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||||
run: make binaryen
|
run: make binaryen
|
||||||
- name: Cache wasi-libc
|
- name: Cache wasi-libc
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-asserts-v5
|
key: wasi-libc-sysroot-linux-asserts-v6
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -267,7 +269,7 @@ jobs:
|
|||||||
- run: make smoketest
|
- run: make smoketest
|
||||||
- run: make wasmtest
|
- run: make wasmtest
|
||||||
- run: make tinygo-baremetal
|
- run: make tinygo-baremetal
|
||||||
build-linux-arm:
|
build-linux-cross:
|
||||||
# Build ARM Linux binaries, ready for release.
|
# Build ARM Linux binaries, ready for release.
|
||||||
# This intentionally uses an older Linux image, so that we compile against
|
# This intentionally uses an older Linux image, so that we compile against
|
||||||
# an older glibc version and therefore are compatible with a wide range of
|
# an older glibc version and therefore are compatible with a wide range of
|
||||||
@@ -276,28 +278,38 @@ jobs:
|
|||||||
# in that process to avoid doing lots of duplicate work and to avoid
|
# in that process to avoid doing lots of duplicate work and to avoid
|
||||||
# complications around precompiled libraries such as compiler-rt shipped as
|
# complications around precompiled libraries such as compiler-rt shipped as
|
||||||
# part of the release tarball.
|
# part of the release tarball.
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
goarch: [ arm, arm64 ]
|
||||||
|
include:
|
||||||
|
- goarch: arm64
|
||||||
|
toolchain: aarch64-linux-gnu
|
||||||
|
libc: arm64
|
||||||
|
- goarch: arm
|
||||||
|
toolchain: arm-linux-gnueabihf
|
||||||
|
libc: armhf
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install --no-install-recommends \
|
sudo apt-get install --no-install-recommends \
|
||||||
qemu-user \
|
qemu-user \
|
||||||
g++-arm-linux-gnueabihf \
|
g++-${{ matrix.toolchain }} \
|
||||||
libc6-dev-armhf-cross
|
libc6-dev-${{ matrix.libc }}-cross
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-v1
|
key: llvm-source-18-linux-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -308,7 +320,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -319,10 +331,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-arm-v1
|
key: llvm-build-18-linux-${{ matrix.goarch }}-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -333,27 +345,27 @@ jobs:
|
|||||||
# Install build dependencies.
|
# Install build dependencies.
|
||||||
sudo apt-get install --no-install-recommends ninja-build
|
sudo apt-get install --no-install-recommends ninja-build
|
||||||
# build!
|
# build!
|
||||||
make llvm-build CROSS=arm-linux-gnueabihf
|
make llvm-build CROSS=${{ matrix.toolchain }}
|
||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-arm-v1
|
key: binaryen-linux-${{ matrix.goarch }}-v4
|
||||||
path: build/wasm-opt
|
path: build/wasm-opt
|
||||||
- name: Build Binaryen
|
- name: Build Binaryen
|
||||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install --no-install-recommends ninja-build
|
sudo apt-get install --no-install-recommends ninja-build
|
||||||
git submodule update --init lib/binaryen
|
git submodule update --init lib/binaryen
|
||||||
make CROSS=arm-linux-gnueabihf binaryen
|
make CROSS=${{ matrix.toolchain }} binaryen
|
||||||
- name: Install fpm
|
- name: Install fpm
|
||||||
run: |
|
run: |
|
||||||
sudo gem install --version 4.0.7 public_suffix
|
sudo gem install --version 4.0.7 public_suffix
|
||||||
@@ -361,9 +373,9 @@ jobs:
|
|||||||
sudo gem install --no-document fpm
|
sudo gem install --no-document fpm
|
||||||
- name: Build TinyGo binary
|
- name: Build TinyGo binary
|
||||||
run: |
|
run: |
|
||||||
make CROSS=arm-linux-gnueabihf
|
make CROSS=${{ matrix.toolchain }}
|
||||||
- name: Download amd64 release
|
- name: Download amd64 release
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
- name: Extract amd64 release
|
- name: Extract amd64 release
|
||||||
@@ -374,129 +386,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp -p build/tinygo build/release/tinygo/bin
|
cp -p build/tinygo build/release/tinygo/bin
|
||||||
cp -p build/wasm-opt build/release/tinygo/bin
|
cp -p build/wasm-opt build/release/tinygo/bin
|
||||||
- name: Create arm release
|
- name: Create ${{ matrix.goarch }} release
|
||||||
run: |
|
run: |
|
||||||
make release deb RELEASEONLY=1 DEB_ARCH=armhf
|
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
|
||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-arm.tar.gz
|
cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
|
||||||
cp -p build/release.deb /tmp/tinygo_armhf.deb
|
cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-arm-double-zipped
|
name: linux-${{ matrix.goarch }}-double-zipped
|
||||||
path: |
|
path: |
|
||||||
/tmp/tinygo.linux-arm.tar.gz
|
/tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
|
||||||
/tmp/tinygo_armhf.deb
|
/tmp/tinygo_${{ matrix.libc }}.deb
|
||||||
build-linux-arm64:
|
|
||||||
# Build ARM64 Linux binaries, ready for release.
|
|
||||||
# It is set to "needs: build-linux" because it modifies the release created
|
|
||||||
# in that process to avoid doing lots of duplicate work and to avoid
|
|
||||||
# complications around precompiled libraries such as compiler-rt shipped as
|
|
||||||
# part of the release tarball.
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
needs: build-linux
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Install apt dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install --no-install-recommends \
|
|
||||||
qemu-user \
|
|
||||||
g++-aarch64-linux-gnu \
|
|
||||||
libc6-dev-arm64-cross \
|
|
||||||
ninja-build
|
|
||||||
- name: Install Go
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: '1.21'
|
|
||||||
cache: true
|
|
||||||
- name: Restore LLVM source cache
|
|
||||||
uses: actions/cache/restore@v3
|
|
||||||
id: cache-llvm-source
|
|
||||||
with:
|
|
||||||
key: llvm-source-16-linux-v1
|
|
||||||
path: |
|
|
||||||
llvm-project/clang/lib/Headers
|
|
||||||
llvm-project/clang/include
|
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
|
||||||
llvm-project/llvm/include
|
|
||||||
- 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@v3
|
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
|
||||||
with:
|
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
|
||||||
path: |
|
|
||||||
llvm-project/clang/lib/Headers
|
|
||||||
llvm-project/clang/include
|
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
|
||||||
llvm-project/llvm/include
|
|
||||||
- name: Restore LLVM build cache
|
|
||||||
uses: actions/cache/restore@v3
|
|
||||||
id: cache-llvm-build
|
|
||||||
with:
|
|
||||||
key: llvm-build-16-linux-arm64-v1
|
|
||||||
path: llvm-build
|
|
||||||
- name: Build LLVM
|
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
# fetch LLVM source
|
|
||||||
rm -rf llvm-project
|
|
||||||
make llvm-source
|
|
||||||
# build!
|
|
||||||
make llvm-build CROSS=aarch64-linux-gnu
|
|
||||||
# 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@v3
|
|
||||||
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@v3
|
|
||||||
id: cache-binaryen
|
|
||||||
with:
|
|
||||||
key: binaryen-linux-arm64-v1
|
|
||||||
path: build/wasm-opt
|
|
||||||
- name: Build Binaryen
|
|
||||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
git submodule update --init lib/binaryen
|
|
||||||
make CROSS=aarch64-linux-gnu binaryen
|
|
||||||
- name: Install fpm
|
|
||||||
run: |
|
|
||||||
sudo gem install --version 4.0.7 public_suffix
|
|
||||||
sudo gem install --version 2.7.6 dotenv
|
|
||||||
sudo gem install --no-document fpm
|
|
||||||
- name: Build TinyGo binary
|
|
||||||
run: |
|
|
||||||
make CROSS=aarch64-linux-gnu
|
|
||||||
- name: Download amd64 release
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: linux-amd64-double-zipped
|
|
||||||
- name: Extract amd64 release
|
|
||||||
run: |
|
|
||||||
mkdir -p build/release
|
|
||||||
tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
|
|
||||||
- name: Modify release
|
|
||||||
run: |
|
|
||||||
cp -p build/tinygo build/release/tinygo/bin
|
|
||||||
cp -p build/wasm-opt build/release/tinygo/bin
|
|
||||||
- name: Create arm64 release
|
|
||||||
run: |
|
|
||||||
make release deb RELEASEONLY=1 DEB_ARCH=arm64
|
|
||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-arm64.tar.gz
|
|
||||||
cp -p build/release.deb /tmp/tinygo_arm64.deb
|
|
||||||
- name: Publish release artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: linux-arm64-double-zipped
|
|
||||||
path: |
|
|
||||||
/tmp/tinygo.linux-arm64.tar.gz
|
|
||||||
/tmp/tinygo_arm64.deb
|
|
||||||
|
|||||||
@@ -25,18 +25,18 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
tinygo/llvm-16
|
tinygo/llvm-18
|
||||||
ghcr.io/${{ github.repository_owner }}/llvm-16
|
ghcr.io/${{ github.repository_owner }}/llvm-18
|
||||||
tags: |
|
tags: |
|
||||||
type=sha,format=long
|
type=sha,format=long
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
@@ -46,13 +46,13 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
- name: Log in to Github Container Registry
|
- name: Log in to Github Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
target: tinygo-llvm-build
|
target: tinygo-llvm-build
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: Nix
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- release
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nix-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Pull musl
|
||||||
|
run: |
|
||||||
|
git submodule update --init lib/musl
|
||||||
|
- name: Restore LLVM source cache
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
id: cache-llvm-source
|
||||||
|
with:
|
||||||
|
key: llvm-source-18-linux-nix-v1
|
||||||
|
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@v4
|
||||||
|
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
|
||||||
|
- 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"
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Command that's part of sizediff.yml. This is put in a separate file so that it
|
||||||
|
# still works after checking out the dev branch (that is, when going from LLVM
|
||||||
|
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
|
||||||
|
|
||||||
|
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 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-18-dev \
|
||||||
|
clang-18 \
|
||||||
|
libclang-18-dev \
|
||||||
|
lld-18
|
||||||
@@ -18,34 +18,26 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
run: |
|
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 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-16-dev \
|
|
||||||
clang-16 \
|
|
||||||
libclang-16-dev \
|
|
||||||
lld-16
|
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-sizediff-v1
|
key: llvm-source-18-sizediff-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/compiler-rt
|
llvm-project/compiler-rt
|
||||||
- name: Download LLVM source
|
- name: Download LLVM source
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Cache Go
|
- name: Cache Go
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
@@ -55,22 +47,25 @@ jobs:
|
|||||||
- name: Save HEAD
|
- name: Save HEAD
|
||||||
run: git branch github-actions-saved-HEAD HEAD
|
run: git branch github-actions-saved-HEAD HEAD
|
||||||
|
|
||||||
# Compute sizes for the dev branch
|
|
||||||
- name: Checkout dev branch
|
|
||||||
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
|
||||||
- name: Build tinygo binary for the dev branch
|
|
||||||
run: go install
|
|
||||||
- name: Determine binary sizes on the dev branch
|
|
||||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
|
||||||
|
|
||||||
# Compute sizes for the PR branch
|
# Compute sizes for the PR branch
|
||||||
- name: Checkout PR branch
|
|
||||||
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
|
|
||||||
- name: Build tinygo binary for the PR branch
|
- name: Build tinygo binary for the PR branch
|
||||||
run: go install
|
run: go install
|
||||||
- name: Determine binary sizes on the PR branch
|
- name: Determine binary sizes on the PR branch
|
||||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
||||||
|
|
||||||
|
# Compute sizes for the dev branch
|
||||||
|
- name: Checkout dev branch
|
||||||
|
run: |
|
||||||
|
git reset --hard origin/dev
|
||||||
|
git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||||
|
- name: Install apt dependencies on the dev branch
|
||||||
|
# this is only needed on a PR that changes the LLVM version
|
||||||
|
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||||
|
- name: Build tinygo binary for the dev branch
|
||||||
|
run: go install
|
||||||
|
- name: Determine binary sizes on the dev branch
|
||||||
|
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||||
|
|
||||||
# Create comment
|
# Create comment
|
||||||
# TODO: add a summary, something like:
|
# TODO: add a summary, something like:
|
||||||
# - overall size difference (percent)
|
# - overall size difference (percent)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -29,19 +29,19 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install ninja binaryen
|
scoop install ninja binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore cached LLVM source
|
- name: Restore cached LLVM source
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-windows-v1
|
key: llvm-source-18-windows-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save cached LLVM source
|
- name: Save cached LLVM source
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -63,10 +63,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore cached LLVM build
|
- name: Restore cached LLVM build
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-windows-v2
|
key: llvm-build-18-windows-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -80,23 +80,23 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save cached LLVM build
|
- name: Save cached LLVM build
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-v5
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
run: make wasi-libc
|
run: make wasi-libc
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
scoop install wasmtime
|
scoop install wasmtime@14.0.4
|
||||||
- name: make gen-device
|
- name: make gen-device
|
||||||
run: make -j3 gen-device
|
run: make -j3 gen-device
|
||||||
- name: Test TinyGo
|
- name: Test TinyGo
|
||||||
@@ -116,7 +116,7 @@ jobs:
|
|||||||
# - have a dobule-zipped artifact when downloaded from the UI
|
# - have a dobule-zipped artifact when downloaded from the UI
|
||||||
# - have a very slow artifact upload
|
# - have a very slow artifact upload
|
||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/release/release.zip
|
path: build/release/release.zip
|
||||||
@@ -126,7 +126,7 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -139,14 +139,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install binaryen
|
scoop install binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
@@ -163,20 +163,20 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
disk-root: "C:"
|
disk-root: "C:"
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
@@ -192,7 +192,7 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -203,16 +203,16 @@ jobs:
|
|||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
scoop install binaryen wasmtime
|
scoop install binaryen && scoop install wasmtime@14.0.4
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ src/device/kendryte/*.go
|
|||||||
src/device/kendryte/*.s
|
src/device/kendryte/*.s
|
||||||
src/device/rp/*.go
|
src/device/rp/*.go
|
||||||
src/device/rp/*.s
|
src/device/rp/*.s
|
||||||
|
src/device/wch/*.go
|
||||||
|
src/device/wch/*.s
|
||||||
vendor
|
vendor
|
||||||
llvm-build
|
llvm-build
|
||||||
llvm-project
|
llvm-project
|
||||||
|
|||||||
+7
-2
@@ -9,10 +9,11 @@
|
|||||||
url = https://github.com/avr-rust/avr-mcu.git
|
url = https://github.com/avr-rust/avr-mcu.git
|
||||||
[submodule "lib/cmsis-svd"]
|
[submodule "lib/cmsis-svd"]
|
||||||
path = lib/cmsis-svd
|
path = lib/cmsis-svd
|
||||||
url = https://github.com/tinygo-org/cmsis-svd
|
url = https://github.com/cmsis-svd/cmsis-svd-data.git
|
||||||
|
branch = main
|
||||||
[submodule "lib/wasi-libc"]
|
[submodule "lib/wasi-libc"]
|
||||||
path = lib/wasi-libc
|
path = lib/wasi-libc
|
||||||
url = https://github.com/CraneStation/wasi-libc
|
url = https://github.com/WebAssembly/wasi-libc
|
||||||
[submodule "lib/picolibc"]
|
[submodule "lib/picolibc"]
|
||||||
path = lib/picolibc
|
path = lib/picolibc
|
||||||
url = https://github.com/keith-packard/picolibc.git
|
url = https://github.com/keith-packard/picolibc.git
|
||||||
@@ -34,3 +35,7 @@
|
|||||||
[submodule "lib/renesas-svd"]
|
[submodule "lib/renesas-svd"]
|
||||||
path = lib/renesas-svd
|
path = lib/renesas-svd
|
||||||
url = https://github.com/tinygo-org/renesas-svd.git
|
url = https://github.com/tinygo-org/renesas-svd.git
|
||||||
|
[submodule "src/net"]
|
||||||
|
path = src/net
|
||||||
|
url = https://github.com/tinygo-org/net.git
|
||||||
|
branch = dev
|
||||||
|
|||||||
+2
-1
@@ -18,7 +18,8 @@ tarball. If you want to help with development of TinyGo itself, you should follo
|
|||||||
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
|
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
|
||||||
build tools to be built. Go is of course necessary to build TinyGo itself.
|
build tools to be built. Go is of course necessary to build TinyGo itself.
|
||||||
|
|
||||||
* Go (1.18+)
|
* Go (1.19+)
|
||||||
|
* GNU Make
|
||||||
* Standard build tools (gcc/clang)
|
* Standard build tools (gcc/clang)
|
||||||
* git
|
* git
|
||||||
* CMake
|
* CMake
|
||||||
|
|||||||
+160
@@ -1,3 +1,163 @@
|
|||||||
|
0.32.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
- fix wasi-libc include headers on Nix
|
||||||
|
- apply OpenOCD commands after target configuration
|
||||||
|
- fix a minor race condition when determining the build tags
|
||||||
|
- support UF2 drives with a space in their name on Linux
|
||||||
|
- add LLVM 18 support
|
||||||
|
- drop support for Go 1.18 to be able to stay up to date
|
||||||
|
|
||||||
|
* **compiler**
|
||||||
|
- move `-panic=trap` support to the compiler/runtime
|
||||||
|
- fix symbol table index for WebAssembly archives
|
||||||
|
- fix ed25519 build errors by adjusting the alias names
|
||||||
|
- add aliases to generic AES functions
|
||||||
|
- fix race condition by temporarily applying a proposed patch
|
||||||
|
- `builder`: keep un-wasm-opt'd .wasm if -work was passed
|
||||||
|
- `builder`: make sure wasm-opt command line is printed if asked
|
||||||
|
- `cgo`: implement shift operations in preprocessor macros
|
||||||
|
- `interp`: checking for methodset existance
|
||||||
|
|
||||||
|
* **standard library**
|
||||||
|
- `machine`: add `__tinygo_spi_tx` function to simulator
|
||||||
|
- `machine`: fix simulator I2C support
|
||||||
|
- `machine`: add GetRNG support to simulator
|
||||||
|
- `machine`: add `TxFifoFreeLevel` for CAN
|
||||||
|
- `os`: add `Link`
|
||||||
|
- `os`: add `FindProcess` for posix
|
||||||
|
- `os`: add `Process.Release` for unix
|
||||||
|
- `os`: add `SetReadDeadline` stub
|
||||||
|
- `os`, `os/signal`: add signal stubs
|
||||||
|
- `os/user`: add stubs for `Lookup{,Group}` and `Group`
|
||||||
|
- `reflect`: use int in `StringHeader` and `SliceHeader` on non-AVR platforms
|
||||||
|
- `reflect`: fix `NumMethods` for Interface type
|
||||||
|
- `runtime`: skip negative sleep durations in sleepTicks
|
||||||
|
|
||||||
|
* **targets**
|
||||||
|
- `esp32`: add I2C support
|
||||||
|
- `rp2040`: move UART0 and UART1 to common file
|
||||||
|
- `rp2040`: make all RP2040 boards available for simulation
|
||||||
|
- `rp2040`: fix timeUnit type
|
||||||
|
- `stm32`: add i2c `Frequency` and `SetBaudRate` function for chips that were missing implementation
|
||||||
|
- `wasm-unknown`: add math and memory builtins that LLVM needs
|
||||||
|
- `wasip1`: replace existing `-target=wasi` support with wasip1 as supported in Go 1.21+
|
||||||
|
|
||||||
|
* **boards**
|
||||||
|
- `adafruit-esp32-feather-v2`: add the Adafruit ESP32 Feather V2
|
||||||
|
- `badger2040-w`: add support for the Badger2040 W
|
||||||
|
- `feather-nrf52840-sense`: fix lack of LXFO
|
||||||
|
- `m5paper`: add support for the M5 Paper
|
||||||
|
- `mksnanov3`: limit programming speed to 1800 kHz
|
||||||
|
- `nucleol476rg`: add stm32 nucleol476rg support
|
||||||
|
- `pico-w`: add the Pico W (which is near-idential to the pico target)
|
||||||
|
- `thingplus-rp2040`, `waveshare-rp2040-zero`: add WS2812 definition
|
||||||
|
- `pca10059-s140v7`: add this variant to the PCA10059 board
|
||||||
|
|
||||||
|
|
||||||
|
0.31.2
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* update the `net` submodule to updated version with `Buffers` implementation
|
||||||
|
|
||||||
|
* **compiler**
|
||||||
|
* `syscall`: add wasm_unknown tag to some additional files so it can compile more code
|
||||||
|
|
||||||
|
* **standard library**
|
||||||
|
* `runtime`: add Frame.Entry field
|
||||||
|
|
||||||
|
|
||||||
|
0.31.1
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* fix Binaryen build in make task
|
||||||
|
* update final build stage of Docker `dev` image to go1.22
|
||||||
|
* only use GHA cache for building Docker `dev` image
|
||||||
|
* update the `net` submodule to latest version
|
||||||
|
|
||||||
|
* **compiler**
|
||||||
|
* `interp`: make getelementptr offsets signed
|
||||||
|
* `interp`: return a proper error message when indexing out of range
|
||||||
|
|
||||||
|
|
||||||
|
0.31.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* remove LLVM 14 support
|
||||||
|
* add LLVM 17 support, and use it by default
|
||||||
|
* add Nix flake support
|
||||||
|
* update bundled Binaryen to version 116
|
||||||
|
* add `ports` subcommand that lists available serial ports for `-port` and `-monitor`
|
||||||
|
* support wasmtime version 14
|
||||||
|
* add `-serial=rtt` for serial output over SWD
|
||||||
|
* add Go 1.22 support and use it by default
|
||||||
|
* change minimum Node.js version from 16 to 18
|
||||||
|
* **compiler**
|
||||||
|
* use the new LLVM pass manager
|
||||||
|
* allow systems with more stack space to allocate larger values on the stack
|
||||||
|
* `build`: fix a crash due to sharing GlobalValues between build instances
|
||||||
|
* `cgo`: add `C._Bool` type
|
||||||
|
* `cgo`: fix calling CGo callback inside generic function
|
||||||
|
* `compileopts`: set `purego` build tag by default so that more packages can be built
|
||||||
|
* `compileopts`: force-enable CGo to avoid build issues
|
||||||
|
* `compiler`: fix crash on type assert on interfaces with no methods
|
||||||
|
* `interp`: print LLVM instruction in traceback
|
||||||
|
* `interp`: support runtime times by running them at runtime
|
||||||
|
* `loader`: enforce Go language version in the type checker (this may break existing programs with an incorrect Go version in go.mod)
|
||||||
|
* `transform`: fix bug in StringToBytes optimization pass
|
||||||
|
* **standard library**
|
||||||
|
* `crypto/tls`: stub out a lot of functions
|
||||||
|
* `internal/task`, `machine`: make TinyGo code usable with "big Go" CGo
|
||||||
|
* `machine`: implement `I2C.SetBaudRate` consistently across chips
|
||||||
|
* `machine`: implement `SPI.Configure` consistently across chips
|
||||||
|
* `machine`: add `DeviceID` for nrf, rp2040, sam, stm32
|
||||||
|
* `machine`: use smaller UART buffer size on atmega chips
|
||||||
|
* `machine/usb`: allow setting a serial number using a linker flag
|
||||||
|
* `math`: support more math functions on baremetal (picolibc) systems
|
||||||
|
* `net`: replace entire net package with a new one based on the netdev driver
|
||||||
|
* `os/user`: add bare-bones implementation of this package
|
||||||
|
* `reflect`: stub `CallSlice` and `FuncOf`
|
||||||
|
* `reflect`: add `TypeFor[T]`
|
||||||
|
* `reflect`: update `IsZero` to Go 1.22 semantics
|
||||||
|
* `reflect`: move indirect values into interface when setting interfaces
|
||||||
|
* `runtime`: stub `Breakpoint`
|
||||||
|
* `sync`: implement trylock
|
||||||
|
* **targets**
|
||||||
|
* `atmega`: use UART double speed mode for fewer errors and higher throughput
|
||||||
|
* `atmega328pb`: refactor to enable extra uart
|
||||||
|
* `avr`: don't compile large parts of picolibc (math, stdio) for LLVM 17 support
|
||||||
|
* `esp32`: switch over to the official SVD file
|
||||||
|
* `esp32c3`: implement USB_SERIAL for USBCDC communication
|
||||||
|
* `esp32c3`: implement I2C
|
||||||
|
* `esp32c3`: implement RNG
|
||||||
|
* `esp32c3`: add more ROM functions and update linker script for the in-progress wifi support
|
||||||
|
* `esp32c3`: update to newer SVD files
|
||||||
|
* `rp2040`: add support for UART hardware flow control
|
||||||
|
* `rp2040`: add definition for `machine.PinToggle`
|
||||||
|
* `rp2040`: set XOSC startup delay multiplier
|
||||||
|
* `samd21`: add support for UART hardware flow control
|
||||||
|
* `samd51`: add support for UART hardware flow control
|
||||||
|
* `wasm`: increase default stack size to 64k for wasi/wasm targets
|
||||||
|
* `wasm`: bump wasi-libc version to SDK 20
|
||||||
|
* `wasm`: remove line of dead code in wasm_exec.js
|
||||||
|
* **new targets/boards**
|
||||||
|
* `qtpy-esp32c3`: add Adafruit QT Py ESP32-C3 board
|
||||||
|
* `mksnanov3`: add support for the MKS Robin Nano V3.x
|
||||||
|
* `nrf52840-generic`: add generic nrf52840 chip support
|
||||||
|
* `thumby`: add support for Thumby
|
||||||
|
* `wasm`: add new `wasm-unknown` target that doesn't depend on WASI or a browser
|
||||||
|
* **boards**
|
||||||
|
* `arduino-mkrwifi1010`, `arduino-nano33`, `nano-rp2040`, `matrixportal-m4`, `metro-m4-airlift`, `pybadge`, `pyportal`: add `ninafw` build tag and some constants for BLE support
|
||||||
|
* `gopher-badge`: fix typo in USB product name
|
||||||
|
* `nano-rp2040`: add UART1 and correct mappings for NINA via UART
|
||||||
|
* `pico`: bump default stack size from 2kB to 8kB
|
||||||
|
* `wioterminal`: expose UART4
|
||||||
|
|
||||||
|
|
||||||
0.30.0
|
0.30.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+22
-19
@@ -1,10 +1,15 @@
|
|||||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||||
FROM golang:1.21 AS tinygo-llvm
|
FROM golang:1.22 AS tinygo-llvm
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y apt-utils make cmake clang-15 ninja-build
|
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
|
||||||
|
rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/var/log/* \
|
||||||
|
/var/tmp/* \
|
||||||
|
/tmp/*
|
||||||
|
|
||||||
COPY ./Makefile /tinygo/Makefile
|
COPY ./GNUmakefile /tinygo/GNUmakefile
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
make llvm-source
|
make llvm-source
|
||||||
@@ -15,26 +20,24 @@ FROM tinygo-llvm AS tinygo-llvm-build
|
|||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
make llvm-build
|
make llvm-build
|
||||||
|
|
||||||
# tinygo-compiler stage builds the compiler itself
|
# tinygo-compiler-build stage builds the compiler itself
|
||||||
FROM tinygo-llvm-build AS tinygo-compiler
|
FROM tinygo-llvm-build AS tinygo-compiler-build
|
||||||
|
|
||||||
COPY . /tinygo
|
COPY . /tinygo
|
||||||
|
|
||||||
# update submodules
|
# build the compiler and tools
|
||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
rm -rf ./lib/*/ && \
|
git submodule update --init && \
|
||||||
git submodule sync && \
|
|
||||||
git submodule update --init --recursive --force
|
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
|
||||||
make
|
|
||||||
|
|
||||||
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
|
|
||||||
FROM tinygo-compiler AS tinygo-tools
|
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
|
||||||
make wasi-libc binaryen && \
|
|
||||||
make gen-device -j4 && \
|
make gen-device -j4 && \
|
||||||
cp build/* $GOPATH/bin/
|
make build/release
|
||||||
|
|
||||||
|
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||||
|
# all the build tools etc).
|
||||||
|
FROM golang:1.22 AS tinygo-compiler
|
||||||
|
|
||||||
|
# Copy tinygo build.
|
||||||
|
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||||
|
|
||||||
|
# Configure the container.
|
||||||
|
ENV PATH="${PATH}:/tinygo/bin"
|
||||||
CMD ["tinygo"]
|
CMD ["tinygo"]
|
||||||
|
|||||||
+90
-39
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
|
|||||||
|
|
||||||
# Try to autodetect LLVM build tools.
|
# Try to autodetect LLVM build tools.
|
||||||
# Versions are listed here in descending priority order.
|
# Versions are listed here in descending priority order.
|
||||||
LLVM_VERSIONS = 16 15 14 13 12 11
|
LLVM_VERSIONS = 18 17 16 15
|
||||||
errifempty = $(if $(1),$(1),$(error $(2)))
|
errifempty = $(if $(1),$(1),$(error $(2)))
|
||||||
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
|
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
|
||||||
toolSearchPathsVersion = $(1)-$(2)
|
toolSearchPathsVersion = $(1)-$(2)
|
||||||
@@ -31,9 +31,7 @@ export GOROOT = $(shell $(GO) env GOROOT)
|
|||||||
|
|
||||||
# Flags to pass to go test.
|
# Flags to pass to go test.
|
||||||
GOTESTFLAGS ?=
|
GOTESTFLAGS ?=
|
||||||
|
GOTESTPKGS ?= ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||||
# md5sum binary
|
|
||||||
MD5SUM = md5sum
|
|
||||||
|
|
||||||
# tinygo binary for tests
|
# tinygo binary for tests
|
||||||
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
|
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
|
||||||
@@ -113,7 +111,7 @@ endif
|
|||||||
|
|
||||||
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
|
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
|
||||||
|
|
||||||
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
|
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontenddriver frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
EXE = .exe
|
EXE = .exe
|
||||||
@@ -130,14 +128,14 @@ ifeq ($(OS),Windows_NT)
|
|||||||
USE_SYSTEM_BINARYEN ?= 1
|
USE_SYSTEM_BINARYEN ?= 1
|
||||||
|
|
||||||
else ifeq ($(shell uname -s),Darwin)
|
else ifeq ($(shell uname -s),Darwin)
|
||||||
MD5SUM = md5
|
MD5SUM ?= md5
|
||||||
|
|
||||||
CGO_LDFLAGS += -lxar
|
CGO_LDFLAGS += -lxar
|
||||||
|
|
||||||
USE_SYSTEM_BINARYEN ?= 1
|
USE_SYSTEM_BINARYEN ?= 1
|
||||||
|
|
||||||
else ifeq ($(shell uname -s),FreeBSD)
|
else ifeq ($(shell uname -s),FreeBSD)
|
||||||
MD5SUM = md5
|
MD5SUM ?= md5
|
||||||
START_GROUP = -Wl,--start-group
|
START_GROUP = -Wl,--start-group
|
||||||
END_GROUP = -Wl,--end-group
|
END_GROUP = -Wl,--end-group
|
||||||
else
|
else
|
||||||
@@ -145,8 +143,11 @@ else
|
|||||||
END_GROUP = -Wl,--end-group
|
END_GROUP = -Wl,--end-group
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# md5sum binary default, can be overridden by an environment variable
|
||||||
|
MD5SUM ?= md5sum
|
||||||
|
|
||||||
# Libraries that should be linked in for the statically linked Clang.
|
# Libraries that should be linked in for the statically linked Clang.
|
||||||
CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
|
CLANG_LIB_NAMES = clangAnalysis clangAPINotes clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
|
||||||
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
|
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
|
||||||
|
|
||||||
# Libraries that should be linked in for the statically linked LLD.
|
# Libraries that should be linked in for the statically linked LLD.
|
||||||
@@ -165,7 +166,7 @@ LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
|
|||||||
# library path (for ninja).
|
# library path (for ninja).
|
||||||
# This list also includes a few tools that are necessary as part of the full
|
# This list also includes a few tools that are necessary as part of the full
|
||||||
# TinyGo build.
|
# TinyGo build.
|
||||||
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
|
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm lld $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
|
||||||
|
|
||||||
# For static linking.
|
# For static linking.
|
||||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||||
@@ -184,7 +185,7 @@ fmt-check:
|
|||||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||||
|
|
||||||
|
|
||||||
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp
|
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp gen-device-wch
|
||||||
ifneq ($(STM32), 0)
|
ifneq ($(STM32), 0)
|
||||||
gen-device: gen-device-stm32
|
gen-device: gen-device-stm32
|
||||||
endif
|
endif
|
||||||
@@ -236,9 +237,13 @@ gen-device-renesas: build/gen-device-svd
|
|||||||
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
|
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
|
||||||
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
||||||
|
|
||||||
|
gen-device-wch: build/gen-device-svd
|
||||||
|
./build/gen-device-svd -source=https://github.com/ch32-rs/ch32-rs/ lib/cmsis-svd/data/WCH-Community/ src/device/wch
|
||||||
|
GO111MODULE=off $(GO) fmt ./src/device/wch
|
||||||
|
|
||||||
# Get LLVM sources.
|
# Get LLVM sources.
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
git clone -b xtensa_release_16.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
git clone -b tinygo_xtensa_release_18.1.2 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||||
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
||||||
|
|
||||||
# Configure LLVM.
|
# Configure LLVM.
|
||||||
@@ -256,7 +261,7 @@ ifneq ($(USE_SYSTEM_BINARYEN),1)
|
|||||||
binaryen: build/wasm-opt$(EXE)
|
binaryen: build/wasm-opt$(EXE)
|
||||||
build/wasm-opt$(EXE):
|
build/wasm-opt$(EXE):
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON -DBUILD_TESTS=OFF $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
||||||
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -265,25 +270,25 @@ endif
|
|||||||
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
|
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
|
||||||
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||||
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||||
cd lib/wasi-libc && make -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
|
cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM)
|
||||||
|
|
||||||
# Check for Node.js used during WASM tests.
|
# Check for Node.js used during WASM tests.
|
||||||
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
||||||
MIN_NODEJS_VERSION=16
|
MIN_NODEJS_VERSION=18
|
||||||
|
|
||||||
.PHONY: check-nodejs-version
|
.PHONY: check-nodejs-version
|
||||||
check-nodejs-version:
|
check-nodejs-version:
|
||||||
ifeq (, $(shell which node))
|
ifeq (, $(shell which node))
|
||||||
@echo "Install NodeJS version 16+ to run tests."; exit 1;
|
@echo "Install NodeJS version 18+ to run tests."; exit 1;
|
||||||
endif
|
endif
|
||||||
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
|
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi
|
||||||
|
|
||||||
# Build the Go compiler.
|
# Build the Go compiler.
|
||||||
tinygo:
|
tinygo:
|
||||||
@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
|
@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" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||||
test: wasi-libc check-nodejs-version
|
test: wasi-libc check-nodejs-version
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
|
||||||
|
|
||||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||||
TEST_PACKAGES_SLOW = \
|
TEST_PACKAGES_SLOW = \
|
||||||
@@ -426,17 +431,17 @@ tinygo-bench-fast:
|
|||||||
|
|
||||||
# Same thing, except for wasi rather than the current platform.
|
# Same thing, except for wasi rather than the current platform.
|
||||||
tinygo-test-wasi:
|
tinygo-test-wasi:
|
||||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
tinygo-test-wasip1:
|
tinygo-test-wasip1:
|
||||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
tinygo-test-wasi-fast:
|
tinygo-test-wasi-fast:
|
||||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
tinygo-test-wasip1-fast:
|
tinygo-test-wasip1-fast:
|
||||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
tinygo-bench-wasi:
|
tinygo-bench-wasi:
|
||||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-bench-wasi-fast:
|
tinygo-bench-wasi-fast:
|
||||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
|
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST)
|
||||||
|
|
||||||
# Test external packages in a large corpus.
|
# Test external packages in a large corpus.
|
||||||
test-corpus:
|
test-corpus:
|
||||||
@@ -444,7 +449,7 @@ test-corpus:
|
|||||||
test-corpus-fast:
|
test-corpus-fast:
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
|
||||||
test-corpus-wasi: wasi-libc
|
test-corpus-wasi: wasi-libc
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasi
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasip1
|
||||||
|
|
||||||
tinygo-baremetal:
|
tinygo-baremetal:
|
||||||
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
|
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
|
||||||
@@ -490,7 +495,7 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/rtcinterrupt
|
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/rtcinterrupt
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/machinetest
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -506,6 +511,8 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test simulated boards on play.tinygo.org
|
# test simulated boards on play.tinygo.org
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||||
@@ -520,7 +527,9 @@ ifneq ($(WASM), 0)
|
|||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/serial
|
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/machinetest
|
||||||
|
@$(MD5SUM) test.wasm
|
||||||
|
$(TINYGO) build -size short -o test.wasm -tags=gopher_badge examples/blinky1
|
||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
endif
|
endif
|
||||||
# test all targets/boards
|
# test all targets/boards
|
||||||
@@ -596,6 +605,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pca10059-s140v7 examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
|
||||||
@@ -614,7 +625,7 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
|
$(TINYGO) build -size short -o test.hex -target=qtpy examples/machinetest
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -652,6 +663,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=badger2040-w examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=tufty2040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=tufty2040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
|
||||||
@@ -668,6 +681,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test pwm
|
# test pwm
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -682,6 +697,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nrf52840-s140v6-uf2-generic examples/machinetest
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(STM32), 0)
|
ifneq ($(STM32), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -697,6 +714,8 @@ ifneq ($(STM32), 0)
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nucleo-l476rg examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
|
||||||
@@ -715,8 +734,12 @@ ifneq ($(STM32), 0)
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
endif
|
endif
|
||||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
$(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
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -743,30 +766,33 @@ ifneq ($(XTENSA), 0)
|
|||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/serial
|
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
|
$(TINYGO) build -size short -o test.bin -target m5stack examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/serial
|
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
$(TINYGO) build -size short -o test.bin -target m5paper examples/machinetest
|
||||||
|
@$(MD5SUM) test.bin
|
||||||
|
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
endif
|
endif
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
|
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
|
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest
|
||||||
@$(MD5SUM) test.bin
|
|
||||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/serial
|
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nanoch32v003 examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
||||||
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm-unknown examples/hello-wasm-unknown
|
||||||
endif
|
endif
|
||||||
# test various compiler flags
|
# test various compiler flags
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
||||||
@@ -775,6 +801,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
||||||
@$(MD5SUM) test.nro
|
@$(MD5SUM) test.nro
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
||||||
@@ -807,7 +835,9 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
|
|||||||
@mkdir -p build/release/tinygo/lib/nrfx
|
@mkdir -p build/release/tinygo/lib/nrfx
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
|
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
|
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
|
||||||
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||||
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
|
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
|
||||||
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
|
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
|
||||||
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
|
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
|
||||||
@@ -834,6 +864,7 @@ endif
|
|||||||
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
|
||||||
|
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
|
||||||
@@ -857,7 +888,15 @@ endif
|
|||||||
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
|
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
|
||||||
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
||||||
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
|
@cp -rp lib/wasi-libc/libc-bottom-half/headers/public build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/generic build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/wasm32 build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/src/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/src/internal build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/src/math build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/src/string build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
|
@cp -rp lib/wasi-libc/libc-top-half/musl/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl
|
||||||
|
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
|
||||||
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
@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-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||||
@cp -rp src build/release/tinygo/src
|
@cp -rp src build/release/tinygo/src
|
||||||
@@ -878,9 +917,21 @@ deb:
|
|||||||
@mkdir -p build/release-deb/usr/local/lib
|
@mkdir -p build/release-deb/usr/local/lib
|
||||||
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
|
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
|
||||||
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
|
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
|
||||||
fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
|
fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
|
||||||
|
|
||||||
ifneq ($(RELEASEONLY), 1)
|
ifneq ($(RELEASEONLY), 1)
|
||||||
release: build/release
|
release: build/release
|
||||||
deb: build/release
|
deb: build/release
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
lint:
|
||||||
|
go run github.com/mgechev/revive -version
|
||||||
|
# TODO: lint more directories!
|
||||||
|
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
|
||||||
|
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
|
||||||
|
# Use 'grep .' to get rid of stray blank line
|
||||||
|
go run github.com/mgechev/revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
|
||||||
|
|
||||||
|
spell:
|
||||||
|
# Check for typos in comments. Skip git submodules etc.
|
||||||
|
go run github.com/client9/misspell/cmd/misspell -i 'ackward,devided,extint,inbetween,programmmer,rela' $$( find . -depth 1 -type d | egrep -w -v 'lib|llvm|src/net' )
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# TinyGo - Go compiler for small places
|
# 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://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) [](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
|
||||||
|
|
||||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
|
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ tinygo flash -target arduino examples/blinky1
|
|||||||
|
|
||||||
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
|
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
|
||||||
|
|
||||||
TinyGo programs can run in Fastly Compute@Edge (https://developer.fastly.com/learning/compute/go/), Fermyon Spin (https://developer.fermyon.com/spin/go-components), wazero (https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
TinyGo programs can run in [Fastly Compute](https://www.fastly.com/documentation/guides/compute/go/), [Fermyon Spin](https://developer.fermyon.com/spin/go-components), [wazero](https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
||||||
|
|
||||||
Here is a small TinyGo program for use by a WASI host application:
|
Here is a small TinyGo program for use by a WASI host application:
|
||||||
|
|
||||||
@@ -54,14 +54,14 @@ func add(x, y uint32) uint32 {
|
|||||||
return x + y
|
return x + y
|
||||||
}
|
}
|
||||||
|
|
||||||
// main is required for the `wasi` target, even if it isn't used.
|
// main is required for the `wasip1` target, even if it isn't used.
|
||||||
func main() {}
|
func main() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
This compiles the above TinyGo program for use on any WASI runtime:
|
This compiles the above TinyGo program for use on any WASI runtime:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
tinygo build -o main.wasm -target=wasi main.go
|
tinygo build -o main.wasm -target=wasip1 main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|||||||
+16
-6
@@ -78,17 +78,27 @@ func makeArchive(arfile *os.File, objs []string) error {
|
|||||||
} else if dbg, err := wasm.Parse(objfile); err == nil {
|
} else if dbg, err := wasm.Parse(objfile); err == nil {
|
||||||
for _, s := range dbg.Sections {
|
for _, s := range dbg.Sections {
|
||||||
switch section := s.(type) {
|
switch section := s.(type) {
|
||||||
case *wasm.SectionImport:
|
case *wasm.SectionLinking:
|
||||||
for _, ln := range section.Entries {
|
for _, symbol := range section.Symbols {
|
||||||
|
if symbol.Flags&wasm.LinkingSymbolFlagUndefined != 0 {
|
||||||
if ln.Kind != wasm.ExtKindFunction {
|
// Don't list undefined functions.
|
||||||
// Not a function
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if symbol.Flags&wasm.LinkingSymbolFlagBindingLocal != 0 {
|
||||||
|
// Don't include local symbols.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if symbol.Kind != wasm.LinkingSymbolKindFunction && symbol.Kind != wasm.LinkingSymbolKindData {
|
||||||
|
// Link functions and data symbols.
|
||||||
|
// Some data symbols need to be included, such as
|
||||||
|
// __log_data.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Include in the archive.
|
||||||
symbolTable = append(symbolTable, struct {
|
symbolTable = append(symbolTable, struct {
|
||||||
name string
|
name string
|
||||||
fileIndex int
|
fileIndex int
|
||||||
}{ln.Field, i})
|
}{symbol.Name, i})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-59
@@ -83,8 +83,7 @@ type packageAction struct {
|
|||||||
FileHashes map[string]string // hash of every file that's part of the package
|
FileHashes map[string]string // hash of every file that's part of the package
|
||||||
EmbeddedFiles map[string]string // hash of all the //go:embed files in the package
|
EmbeddedFiles map[string]string // hash of all the //go:embed files in the package
|
||||||
Imports map[string]string // map from imported package to action ID hash
|
Imports map[string]string // map from imported package to action ID hash
|
||||||
OptLevel int // LLVM optimization level (0-3)
|
OptLevel string // LLVM optimization level (O0, O1, O2, Os, Oz)
|
||||||
SizeLevel int // LLVM optimization for size level (0-2)
|
|
||||||
UndefinedGlobals []string // globals that are left as external globals (no initializer)
|
UndefinedGlobals []string // globals that are left as external globals (no initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +114,30 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
cacheDir = tmpdir
|
cacheDir = tmpdir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create default global values.
|
||||||
|
globalValues := map[string]map[string]string{
|
||||||
|
"runtime": {
|
||||||
|
"buildVersion": goenv.Version(),
|
||||||
|
},
|
||||||
|
"testing": {},
|
||||||
|
}
|
||||||
|
if config.TestConfig.CompileTestBinary {
|
||||||
|
// The testing.testBinary is set to "1" when in a test.
|
||||||
|
// This is needed for testing.Testing() to work correctly.
|
||||||
|
globalValues["testing"]["testBinary"] = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy over explicitly set global values, like
|
||||||
|
// -ldflags="-X main.Version="1.0"
|
||||||
|
for pkgPath, vals := range config.Options.GlobalValues {
|
||||||
|
if _, ok := globalValues[pkgPath]; !ok {
|
||||||
|
globalValues[pkgPath] = map[string]string{}
|
||||||
|
}
|
||||||
|
for k, v := range vals {
|
||||||
|
globalValues[pkgPath][k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for a libc dependency.
|
// Check for a libc dependency.
|
||||||
// As a side effect, this also creates the headers for the given libc, if
|
// As a side effect, this also creates the headers for the given libc, if
|
||||||
// the libc needs them.
|
// the libc needs them.
|
||||||
@@ -145,6 +168,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
return BuildResult{}, errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
return BuildResult{}, errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
||||||
}
|
}
|
||||||
libcDependencies = append(libcDependencies, dummyCompileJob(path))
|
libcDependencies = append(libcDependencies, dummyCompileJob(path))
|
||||||
|
case "wasmbuiltins":
|
||||||
|
libcJob, unlock, err := WasmBuiltins.load(config, tmpdir)
|
||||||
|
if err != nil {
|
||||||
|
return BuildResult{}, err
|
||||||
|
}
|
||||||
|
defer unlock()
|
||||||
|
libcDependencies = append(libcDependencies, libcJob)
|
||||||
case "mingw-w64":
|
case "mingw-w64":
|
||||||
_, unlock, err := MinGW.load(config, tmpdir)
|
_, unlock, err := MinGW.load(config, tmpdir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -158,7 +188,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
return BuildResult{}, fmt.Errorf("unknown libc: %s", config.Target.Libc)
|
return BuildResult{}, fmt.Errorf("unknown libc: %s", config.Target.Libc)
|
||||||
}
|
}
|
||||||
|
|
||||||
optLevel, sizeLevel, _ := config.OptLevels()
|
optLevel, speedLevel, sizeLevel := config.OptLevel()
|
||||||
compilerConfig := &compiler.Config{
|
compilerConfig := &compiler.Config{
|
||||||
Triple: config.Triple(),
|
Triple: config.Triple(),
|
||||||
CPU: config.CPU(),
|
CPU: config.CPU(),
|
||||||
@@ -169,13 +199,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
CodeModel: config.CodeModel(),
|
CodeModel: config.CodeModel(),
|
||||||
RelocationModel: config.RelocationModel(),
|
RelocationModel: config.RelocationModel(),
|
||||||
SizeLevel: sizeLevel,
|
SizeLevel: sizeLevel,
|
||||||
TinyGoVersion: goenv.Version,
|
TinyGoVersion: goenv.Version(),
|
||||||
|
|
||||||
Scheduler: config.Scheduler(),
|
Scheduler: config.Scheduler(),
|
||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.StackSize(),
|
DefaultStackSize: config.StackSize(),
|
||||||
|
MaxStackAlloc: config.MaxStackAlloc(),
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
||||||
|
PanicStrategy: config.PanicStrategy(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the target machine, which is the LLVM object that contains all
|
// Load the target machine, which is the LLVM object that contains all
|
||||||
@@ -188,7 +220,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
defer machine.Dispose()
|
defer machine.Dispose()
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, pkgName, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, pkgName, types.Config{
|
||||||
Sizes: compiler.Sizes(machine),
|
Sizes: compiler.Sizes(machine),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -217,34 +249,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
var packageJobs []*compileJob
|
var packageJobs []*compileJob
|
||||||
packageActionIDJobs := make(map[string]*compileJob)
|
packageActionIDJobs := make(map[string]*compileJob)
|
||||||
|
|
||||||
if config.Options.GlobalValues == nil {
|
|
||||||
config.Options.GlobalValues = make(map[string]map[string]string)
|
|
||||||
}
|
|
||||||
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
|
|
||||||
version := goenv.Version
|
|
||||||
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
|
|
||||||
version += "-" + goenv.GitSha1
|
|
||||||
}
|
|
||||||
if config.Options.GlobalValues["runtime"] == nil {
|
|
||||||
config.Options.GlobalValues["runtime"] = make(map[string]string)
|
|
||||||
}
|
|
||||||
config.Options.GlobalValues["runtime"]["buildVersion"] = version
|
|
||||||
}
|
|
||||||
if config.TestConfig.CompileTestBinary {
|
|
||||||
// The testing.testBinary is set to "1" when in a test.
|
|
||||||
// This is needed for testing.Testing() to work correctly.
|
|
||||||
if config.Options.GlobalValues["testing"] == nil {
|
|
||||||
config.Options.GlobalValues["testing"] = make(map[string]string)
|
|
||||||
}
|
|
||||||
config.Options.GlobalValues["testing"]["testBinary"] = "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
var embedFileObjects []*compileJob
|
var embedFileObjects []*compileJob
|
||||||
for _, pkg := range lprogram.Sorted() {
|
for _, pkg := range lprogram.Sorted() {
|
||||||
pkg := pkg // necessary to avoid a race condition
|
pkg := pkg // necessary to avoid a race condition
|
||||||
|
|
||||||
var undefinedGlobals []string
|
var undefinedGlobals []string
|
||||||
for name := range config.Options.GlobalValues[pkg.Pkg.Path()] {
|
for name := range globalValues[pkg.Pkg.Path()] {
|
||||||
undefinedGlobals = append(undefinedGlobals, name)
|
undefinedGlobals = append(undefinedGlobals, name)
|
||||||
}
|
}
|
||||||
sort.Strings(undefinedGlobals)
|
sort.Strings(undefinedGlobals)
|
||||||
@@ -321,7 +331,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
EmbeddedFiles: make(map[string]string, len(allFiles)),
|
EmbeddedFiles: make(map[string]string, len(allFiles)),
|
||||||
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
|
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
|
||||||
OptLevel: optLevel,
|
OptLevel: optLevel,
|
||||||
SizeLevel: sizeLevel,
|
|
||||||
UndefinedGlobals: undefinedGlobals,
|
UndefinedGlobals: undefinedGlobals,
|
||||||
}
|
}
|
||||||
for filePath, hash := range pkg.FileHashes {
|
for filePath, hash := range pkg.FileHashes {
|
||||||
@@ -532,13 +541,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
irbuilder := mod.Context().NewBuilder()
|
irbuilder := mod.Context().NewBuilder()
|
||||||
defer irbuilder.Dispose()
|
defer irbuilder.Dispose()
|
||||||
irbuilder.SetInsertPointAtEnd(block)
|
irbuilder.SetInsertPointAtEnd(block)
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
for _, pkg := range lprogram.Sorted() {
|
for _, pkg := range lprogram.Sorted() {
|
||||||
pkgInit := mod.NamedFunction(pkg.Pkg.Path() + ".init")
|
pkgInit := mod.NamedFunction(pkg.Pkg.Path() + ".init")
|
||||||
if pkgInit.IsNil() {
|
if pkgInit.IsNil() {
|
||||||
panic("init not found for " + pkg.Pkg.Path())
|
panic("init not found for " + pkg.Pkg.Path())
|
||||||
}
|
}
|
||||||
irbuilder.CreateCall(pkgInit.GlobalValueType(), pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
|
irbuilder.CreateCall(pkgInit.GlobalValueType(), pkgInit, []llvm.Value{llvm.Undef(ptrType)}, "")
|
||||||
}
|
}
|
||||||
irbuilder.CreateRetVoid()
|
irbuilder.CreateRetVoid()
|
||||||
|
|
||||||
@@ -573,7 +582,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
|
|
||||||
// Run all optimization passes, which are much more effective now
|
// Run all optimization passes, which are much more effective now
|
||||||
// that the optimizer can see the whole program at once.
|
// that the optimizer can see the whole program at once.
|
||||||
err := optimizeProgram(mod, config)
|
err := optimizeProgram(mod, config, globalValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -662,7 +671,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
job := &compileJob{
|
job := &compileJob{
|
||||||
description: "compile extra file " + path,
|
description: "compile extra file " + path,
|
||||||
run: func(job *compileJob) error {
|
run: func(job *compileJob) error {
|
||||||
result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(), config.Options.PrintCommands)
|
result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(false), config.Options.PrintCommands)
|
||||||
job.result = result
|
job.result = result
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
@@ -743,17 +752,17 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
if config.GOOS() == "windows" {
|
if config.GOOS() == "windows" {
|
||||||
// Options for the MinGW wrapper for the lld COFF linker.
|
// Options for the MinGW wrapper for the lld COFF linker.
|
||||||
ldflags = append(ldflags,
|
ldflags = append(ldflags,
|
||||||
"-Xlink=/opt:lldlto="+strconv.Itoa(optLevel),
|
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),
|
||||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
|
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
|
||||||
} else if config.GOOS() == "darwin" {
|
} else if config.GOOS() == "darwin" {
|
||||||
// Options for the ld64-compatible lld linker.
|
// Options for the ld64-compatible lld linker.
|
||||||
ldflags = append(ldflags,
|
ldflags = append(ldflags,
|
||||||
"--lto-O"+strconv.Itoa(optLevel),
|
"--lto-O"+strconv.Itoa(speedLevel),
|
||||||
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
|
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
|
||||||
} else {
|
} else {
|
||||||
// Options for the ELF linker.
|
// Options for the ELF linker.
|
||||||
ldflags = append(ldflags,
|
ldflags = append(ldflags,
|
||||||
"--lto-O"+strconv.Itoa(optLevel),
|
"--lto-O"+strconv.Itoa(speedLevel),
|
||||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
|
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -764,7 +773,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
if sizeLevel >= 2 {
|
if sizeLevel >= 2 {
|
||||||
// Workaround with roughly the same effect as
|
// Workaround with roughly the same effect as
|
||||||
// https://reviews.llvm.org/D119342.
|
// https://reviews.llvm.org/D119342.
|
||||||
// Can hopefully be removed in LLVM 15.
|
// Can hopefully be removed in LLVM 19.
|
||||||
ldflags = append(ldflags,
|
ldflags = append(ldflags,
|
||||||
"-mllvm", "--rotation-max-header-size=0")
|
"-mllvm", "--rotation-max-header-size=0")
|
||||||
}
|
}
|
||||||
@@ -807,21 +816,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
|
|
||||||
// Run wasm-opt for wasm binaries
|
// Run wasm-opt for wasm binaries
|
||||||
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
||||||
var opt string
|
optLevel, _, _ := config.OptLevel()
|
||||||
switch config.Options.Opt {
|
opt := "-" + optLevel
|
||||||
case "none", "0":
|
|
||||||
opt = "-O0"
|
|
||||||
case "1":
|
|
||||||
opt = "-O1"
|
|
||||||
case "2":
|
|
||||||
opt = "-O2"
|
|
||||||
case "s":
|
|
||||||
opt = "-Os"
|
|
||||||
case "z":
|
|
||||||
opt = "-Oz"
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown opt level: %q", config.Options.Opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
|
|
||||||
@@ -829,13 +825,25 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
args = append(args, "--asyncify")
|
args = append(args, "--asyncify")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exeunopt := result.Executable
|
||||||
|
|
||||||
|
if config.Options.Work {
|
||||||
|
// Keep the work direction around => don't overwrite the .wasm binary with the optimized version
|
||||||
|
exeunopt += ".pre-wasm-opt"
|
||||||
|
os.Rename(result.Executable, exeunopt)
|
||||||
|
}
|
||||||
|
|
||||||
args = append(args,
|
args = append(args,
|
||||||
opt,
|
opt,
|
||||||
"-g",
|
"-g",
|
||||||
result.Executable,
|
exeunopt,
|
||||||
"--output", result.Executable,
|
"--output", result.Executable,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if config.Options.PrintCommands != nil {
|
||||||
|
config.Options.PrintCommands(goenv.Get("WASMOPT"), args...)
|
||||||
|
}
|
||||||
|
|
||||||
cmd := exec.Command(goenv.Get("WASMOPT"), args...)
|
cmd := exec.Command(goenv.Get("WASMOPT"), args...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
@@ -1042,7 +1050,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
|
|||||||
// optimizeProgram runs a series of optimizations and transformations that are
|
// optimizeProgram runs a series of optimizations and transformations that are
|
||||||
// needed to convert a program to its final form. Some transformations are not
|
// needed to convert a program to its final form. Some transformations are not
|
||||||
// optional and must be run as the compiler expects them to run.
|
// optional and must be run as the compiler expects them to run.
|
||||||
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues map[string]map[string]string) error {
|
||||||
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
|
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1061,15 +1069,14 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert values from -ldflags="-X ..." into the IR.
|
// Insert values from -ldflags="-X ..." into the IR.
|
||||||
err = setGlobalValues(mod, config.Options.GlobalValues)
|
err = setGlobalValues(mod, globalValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization levels here are roughly the same as Clang, but probably not
|
// Run most of the whole-program optimizations (including the whole
|
||||||
// exactly.
|
// O0/O1/O2/Os/Oz optimization pipeline).
|
||||||
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
|
errs := transform.Optimize(mod, config)
|
||||||
errs := transform.Optimize(mod, config, optLevel, sizeLevel, inlinerThreshold)
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,14 +27,16 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
"cortex-m33",
|
"cortex-m33",
|
||||||
"cortex-m4",
|
"cortex-m4",
|
||||||
"cortex-m7",
|
"cortex-m7",
|
||||||
|
"ch32v003",
|
||||||
"esp32c3",
|
"esp32c3",
|
||||||
"fe310",
|
"fe310",
|
||||||
"gameboy-advance",
|
"gameboy-advance",
|
||||||
"k210",
|
"k210",
|
||||||
"nintendoswitch",
|
"nintendoswitch",
|
||||||
"riscv-qemu",
|
"riscv-qemu",
|
||||||
"wasi",
|
"wasip1",
|
||||||
"wasm",
|
"wasm",
|
||||||
|
"wasm-unknown",
|
||||||
}
|
}
|
||||||
if hasBuiltinTools {
|
if hasBuiltinTools {
|
||||||
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
|
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
|
||||||
@@ -74,7 +75,6 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
|
|
||||||
func testClangAttributes(t *testing.T, options *compileopts.Options) {
|
func testClangAttributes(t *testing.T, options *compileopts.Options) {
|
||||||
testDir := t.TempDir()
|
testDir := t.TempDir()
|
||||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
|
||||||
|
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
defer ctx.Dispose()
|
defer ctx.Dispose()
|
||||||
@@ -84,9 +84,8 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
|
|||||||
t.Fatalf("could not load target: %s", err)
|
t.Fatalf("could not load target: %s", err)
|
||||||
}
|
}
|
||||||
config := compileopts.Config{
|
config := compileopts.Config{
|
||||||
Options: options,
|
Options: options,
|
||||||
Target: target,
|
Target: target,
|
||||||
ClangHeaders: clangHeaderPath,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a very simple C input file.
|
// Create a very simple C input file.
|
||||||
@@ -98,7 +97,7 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
|
|||||||
|
|
||||||
// Compile this file using Clang.
|
// Compile this file using Clang.
|
||||||
outpath := filepath.Join(testDir, "test.bc")
|
outpath := filepath.Join(testDir, "test.bc")
|
||||||
flags := append([]string{"-c", "-emit-llvm", "-o", outpath, srcpath}, config.CFlags()...)
|
flags := append([]string{"-c", "-emit-llvm", "-o", outpath, srcpath}, config.CFlags(false)...)
|
||||||
if config.GOOS() == "darwin" {
|
if config.GOOS() == "darwin" {
|
||||||
// Silence some warnings that happen when testing GOOS=darwin on
|
// Silence some warnings that happen when testing GOOS=darwin on
|
||||||
// something other than MacOS.
|
// something other than MacOS.
|
||||||
|
|||||||
+34
-10
@@ -77,6 +77,15 @@ func ReadBuildID() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return raw[4:], nil
|
return raw[4:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normally we would have found a build ID by now. But not on Nix,
|
||||||
|
// unfortunately, because Nix adds -no_uuid for some reason:
|
||||||
|
// https://github.com/NixOS/nixpkgs/issues/178366
|
||||||
|
// Fall back to the same implementation that we use for Windows.
|
||||||
|
id, err := readRawGoBuildID(f, 32*1024)
|
||||||
|
if len(id) != 0 || err != nil {
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// On other platforms (such as Windows) there isn't such a convenient
|
// On other platforms (such as Windows) there isn't such a convenient
|
||||||
// build ID. Luckily, Go does have an equivalent of the build ID, which
|
// build ID. Luckily, Go does have an equivalent of the build ID, which
|
||||||
@@ -88,16 +97,31 @@ func ReadBuildID() ([]byte, error) {
|
|||||||
// directly. Luckily the build ID is always at the start of the file.
|
// directly. Luckily the build ID is always at the start of the file.
|
||||||
// For details, see:
|
// For details, see:
|
||||||
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
|
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
|
||||||
fileStart := make([]byte, 4096)
|
id, err := readRawGoBuildID(f, 4096)
|
||||||
_, err := io.ReadFull(f, fileStart)
|
if len(id) != 0 || err != nil {
|
||||||
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
|
return id, err
|
||||||
if index < 0 || index > len(fileStart)-103 {
|
|
||||||
return nil, fmt.Errorf("could not find build id in %s", err)
|
|
||||||
}
|
|
||||||
buf := fileStart[index : index+103]
|
|
||||||
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
|
|
||||||
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("could not find build ID in %s", executable)
|
return nil, fmt.Errorf("could not find build ID in %v", executable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Go toolchain stores a build ID in the binary that we can use, as a
|
||||||
|
// fallback if binary file specific build IDs can't be obtained.
|
||||||
|
// This function reads that build ID from the binary.
|
||||||
|
func readRawGoBuildID(f *os.File, prefixSize int) ([]byte, error) {
|
||||||
|
fileStart := make([]byte, prefixSize)
|
||||||
|
_, err := io.ReadFull(f, fileStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read build id from %s: %v", f.Name(), err)
|
||||||
|
}
|
||||||
|
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
|
||||||
|
if index < 0 || index > len(fileStart)-103 {
|
||||||
|
return nil, fmt.Errorf("could not find build id in %s", f.Name())
|
||||||
|
}
|
||||||
|
buf := fileStart[index : index+103]
|
||||||
|
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
|
||||||
|
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -8,14 +8,14 @@ import (
|
|||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
// These are the GENERIC_SOURCES according to CMakeList.txt except for
|
||||||
|
// divmodsi4.c and udivmodsi4.c.
|
||||||
var genericBuiltins = []string{
|
var genericBuiltins = []string{
|
||||||
"absvdi2.c",
|
"absvdi2.c",
|
||||||
"absvsi2.c",
|
"absvsi2.c",
|
||||||
"absvti2.c",
|
"absvti2.c",
|
||||||
"adddf3.c",
|
"adddf3.c",
|
||||||
"addsf3.c",
|
"addsf3.c",
|
||||||
"addtf3.c",
|
|
||||||
"addvdi3.c",
|
"addvdi3.c",
|
||||||
"addvsi3.c",
|
"addvsi3.c",
|
||||||
"addvti3.c",
|
"addvti3.c",
|
||||||
@@ -40,12 +40,12 @@ var genericBuiltins = []string{
|
|||||||
"divdf3.c",
|
"divdf3.c",
|
||||||
"divdi3.c",
|
"divdi3.c",
|
||||||
"divmoddi4.c",
|
"divmoddi4.c",
|
||||||
|
//"divmodsi4.c",
|
||||||
|
"divmodti4.c",
|
||||||
"divsc3.c",
|
"divsc3.c",
|
||||||
"divsf3.c",
|
"divsf3.c",
|
||||||
"divsi3.c",
|
"divsi3.c",
|
||||||
"divtc3.c",
|
|
||||||
"divti3.c",
|
"divti3.c",
|
||||||
"divtf3.c",
|
|
||||||
"extendsfdf2.c",
|
"extendsfdf2.c",
|
||||||
"extendhfsf2.c",
|
"extendhfsf2.c",
|
||||||
"ffsdi2.c",
|
"ffsdi2.c",
|
||||||
@@ -91,7 +91,6 @@ var genericBuiltins = []string{
|
|||||||
"mulsc3.c",
|
"mulsc3.c",
|
||||||
"mulsf3.c",
|
"mulsf3.c",
|
||||||
"multi3.c",
|
"multi3.c",
|
||||||
"multf3.c",
|
|
||||||
"mulvdi3.c",
|
"mulvdi3.c",
|
||||||
"mulvsi3.c",
|
"mulvsi3.c",
|
||||||
"mulvti3.c",
|
"mulvti3.c",
|
||||||
@@ -111,13 +110,11 @@ var genericBuiltins = []string{
|
|||||||
"popcountti2.c",
|
"popcountti2.c",
|
||||||
"powidf2.c",
|
"powidf2.c",
|
||||||
"powisf2.c",
|
"powisf2.c",
|
||||||
"powitf2.c",
|
|
||||||
"subdf3.c",
|
"subdf3.c",
|
||||||
"subsf3.c",
|
"subsf3.c",
|
||||||
"subvdi3.c",
|
"subvdi3.c",
|
||||||
"subvsi3.c",
|
"subvsi3.c",
|
||||||
"subvti3.c",
|
"subvti3.c",
|
||||||
"subtf3.c",
|
|
||||||
"trampoline_setup.c",
|
"trampoline_setup.c",
|
||||||
"truncdfhf2.c",
|
"truncdfhf2.c",
|
||||||
"truncdfsf2.c",
|
"truncdfsf2.c",
|
||||||
@@ -126,6 +123,7 @@ var genericBuiltins = []string{
|
|||||||
"ucmpti2.c",
|
"ucmpti2.c",
|
||||||
"udivdi3.c",
|
"udivdi3.c",
|
||||||
"udivmoddi4.c",
|
"udivmoddi4.c",
|
||||||
|
//"udivmodsi4.c",
|
||||||
"udivmodti4.c",
|
"udivmodti4.c",
|
||||||
"udivsi3.c",
|
"udivsi3.c",
|
||||||
"udivti3.c",
|
"udivti3.c",
|
||||||
|
|||||||
+25
-13
@@ -1,5 +1,12 @@
|
|||||||
//go:build byollvm
|
//go:build byollvm
|
||||||
|
|
||||||
|
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||||
|
// This file needs to be updated each LLVM release.
|
||||||
|
// There are a few small modifications to make, like:
|
||||||
|
// * ExecuteAssembler is made non-static.
|
||||||
|
// * The struct AssemblerImplementation is moved to cc1as.h so it can be
|
||||||
|
// included elsewhere.
|
||||||
|
|
||||||
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
|
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
@@ -21,8 +28,8 @@
|
|||||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||||
#include "clang/Frontend/Utils.h"
|
#include "clang/Frontend/Utils.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/MC/MCAsmBackend.h"
|
#include "llvm/MC/MCAsmBackend.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
@@ -46,7 +53,6 @@
|
|||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/FormattedStream.h"
|
#include "llvm/Support/FormattedStream.h"
|
||||||
#include "llvm/Support/Host.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
#include "llvm/Support/Process.h"
|
#include "llvm/Support/Process.h"
|
||||||
@@ -55,6 +61,8 @@
|
|||||||
#include "llvm/Support/TargetSelect.h"
|
#include "llvm/Support/TargetSelect.h"
|
||||||
#include "llvm/Support/Timer.h"
|
#include "llvm/Support/Timer.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/TargetParser/Host.h"
|
||||||
|
#include "llvm/TargetParser/Triple.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
@@ -74,10 +82,10 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
// Parse the arguments.
|
// Parse the arguments.
|
||||||
const OptTable &OptTbl = getDriverOptTable();
|
const OptTable &OptTbl = getDriverOptTable();
|
||||||
|
|
||||||
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
|
llvm::opt::Visibility VisibilityMask(options::CC1AsOption);
|
||||||
unsigned MissingArgIndex, MissingArgCount;
|
unsigned MissingArgIndex, MissingArgCount;
|
||||||
InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
|
InputArgList Args =
|
||||||
IncludedFlagsBitmask);
|
OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, VisibilityMask);
|
||||||
|
|
||||||
// Check for missing argument error.
|
// Check for missing argument error.
|
||||||
if (MissingArgCount) {
|
if (MissingArgCount) {
|
||||||
@@ -90,7 +98,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
|
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
|
||||||
auto ArgString = A->getAsString(Args);
|
auto ArgString = A->getAsString(Args);
|
||||||
std::string Nearest;
|
std::string Nearest;
|
||||||
if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
|
if (OptTbl.findNearest(ArgString, Nearest, VisibilityMask) > 1)
|
||||||
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
|
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
|
||||||
else
|
else
|
||||||
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
|
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
|
||||||
@@ -151,8 +159,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
|
|
||||||
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
||||||
auto Split = StringRef(Arg).split('=');
|
auto Split = StringRef(Arg).split('=');
|
||||||
Opts.DebugPrefixMap.insert(
|
Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
|
||||||
{std::string(Split.first), std::string(Split.second)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frontend Options
|
// Frontend Options
|
||||||
@@ -225,6 +232,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
.Case("default", EmitDwarfUnwindType::Default);
|
.Case("default", EmitDwarfUnwindType::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opts.EmitCompactUnwindNonCanonical =
|
||||||
|
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
||||||
|
|
||||||
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
@@ -260,8 +270,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
||||||
|
|
||||||
if (std::error_code EC = Buffer.getError()) {
|
if (std::error_code EC = Buffer.getError()) {
|
||||||
Error = EC.message();
|
return Diags.Report(diag::err_fe_error_reading)
|
||||||
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
|
<< Opts.InputFile << EC.message();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceMgr SrcMgr;
|
SourceMgr SrcMgr;
|
||||||
@@ -278,6 +288,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
|
|
||||||
MCTargetOptions MCOptions;
|
MCTargetOptions MCOptions;
|
||||||
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
|
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
|
||||||
|
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
||||||
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
||||||
|
|
||||||
std::unique_ptr<MCAsmInfo> MAI(
|
std::unique_ptr<MCAsmInfo> MAI(
|
||||||
@@ -510,9 +521,10 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
|||||||
if (Asm.ShowHelp) {
|
if (Asm.ShowHelp) {
|
||||||
getDriverOptTable().printHelp(
|
getDriverOptTable().printHelp(
|
||||||
llvm::outs(), "clang -cc1as [options] file...",
|
llvm::outs(), "clang -cc1as [options] file...",
|
||||||
"Clang Integrated Assembler",
|
"Clang Integrated Assembler", /*ShowHidden=*/false,
|
||||||
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
|
/*ShowAllAliases=*/false,
|
||||||
/*ShowAllAliases=*/false);
|
llvm::opt::Visibility(driver::options::CC1AsOption));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -1,3 +1,6 @@
|
|||||||
|
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||||
|
// See cc1as.cpp for details.
|
||||||
|
|
||||||
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
|
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
@@ -44,7 +47,7 @@ struct AssemblerInvocation {
|
|||||||
std::string DwarfDebugFlags;
|
std::string DwarfDebugFlags;
|
||||||
std::string DwarfDebugProducer;
|
std::string DwarfDebugProducer;
|
||||||
std::string DebugCompilationDir;
|
std::string DebugCompilationDir;
|
||||||
std::map<const std::string, const std::string> DebugPrefixMap;
|
llvm::SmallVector<std::pair<std::string, std::string>, 0> DebugPrefixMap;
|
||||||
llvm::DebugCompressionType CompressDebugSections =
|
llvm::DebugCompressionType CompressDebugSections =
|
||||||
llvm::DebugCompressionType::None;
|
llvm::DebugCompressionType::None;
|
||||||
std::string MainFileName;
|
std::string MainFileName;
|
||||||
@@ -89,6 +92,10 @@ struct AssemblerInvocation {
|
|||||||
/// Whether to emit DWARF unwind info.
|
/// Whether to emit DWARF unwind info.
|
||||||
EmitDwarfUnwindType EmitDwarfUnwind;
|
EmitDwarfUnwindType EmitDwarfUnwind;
|
||||||
|
|
||||||
|
// Whether to emit compact-unwind for non-canonical entries.
|
||||||
|
// Note: maybe overriden by other constraints.
|
||||||
|
unsigned EmitCompactUnwindNonCanonical : 1;
|
||||||
|
|
||||||
/// The name of the relocation model to use.
|
/// The name of the relocation model to use.
|
||||||
std::string RelocationModel;
|
std::string RelocationModel;
|
||||||
|
|
||||||
@@ -128,6 +135,7 @@ public:
|
|||||||
DwarfVersion = 0;
|
DwarfVersion = 0;
|
||||||
EmbedBitcode = 0;
|
EmbedBitcode = 0;
|
||||||
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
||||||
|
EmitCompactUnwindNonCanonical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
#include <clang/FrontendTool/Utils.h>
|
#include <clang/FrontendTool/Utils.h>
|
||||||
#include <llvm/ADT/IntrusiveRefCntPtr.h>
|
#include <llvm/ADT/IntrusiveRefCntPtr.h>
|
||||||
#include <llvm/Option/Option.h>
|
#include <llvm/Option/Option.h>
|
||||||
#include <llvm/Support/Host.h>
|
#include <llvm/TargetParser/Host.h>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|||||||
+2
-5
@@ -27,19 +27,16 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if major != 1 || minor < 18 || minor > 21 {
|
if major != 1 || minor < 19 || minor > 22 {
|
||||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
// 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
|
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||||
return nil, fmt.Errorf("requires go version 1.18 through 1.21, got go%d.%d", major, minor)
|
return nil, fmt.Errorf("requires go version 1.19 through 1.22, got go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
|
||||||
|
|
||||||
return &compileopts.Config{
|
return &compileopts.Config{
|
||||||
Options: options,
|
Options: options,
|
||||||
Target: spec,
|
Target: spec,
|
||||||
GoMinorVersion: minor,
|
GoMinorVersion: minor,
|
||||||
ClangHeaders: clangHeaderPath,
|
|
||||||
TestConfig: options.TestConfig,
|
TestConfig: options.TestConfig,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
-105
@@ -1,105 +0,0 @@
|
|||||||
package builder
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io/fs"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"tinygo.org/x/go-llvm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// getClangHeaderPath returns the path to the built-in Clang headers. It tries
|
|
||||||
// multiple locations, which should make it find the directory when installed in
|
|
||||||
// various ways.
|
|
||||||
func getClangHeaderPath(TINYGOROOT string) string {
|
|
||||||
// Check whether we're running from the source directory.
|
|
||||||
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
|
|
||||||
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether we're running from the installation directory.
|
|
||||||
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
|
|
||||||
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// It looks like we are built with a system-installed LLVM. Do a last
|
|
||||||
// attempt: try to use Clang headers relative to the clang binary.
|
|
||||||
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
|
||||||
for _, cmdName := range commands["clang"] {
|
|
||||||
binpath, err := exec.LookPath(cmdName)
|
|
||||||
if err == nil {
|
|
||||||
// This should be the command that will also be used by
|
|
||||||
// execCommand. To avoid inconsistencies, make sure we use the
|
|
||||||
// headers relative to this command.
|
|
||||||
binpath, err = filepath.EvalSymlinks(binpath)
|
|
||||||
if err != nil {
|
|
||||||
// Unexpected.
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// Example executable:
|
|
||||||
// /usr/lib/llvm-9/bin/clang
|
|
||||||
// Example include path:
|
|
||||||
// /usr/lib/llvm-9/lib64/clang/9.0.1/include/
|
|
||||||
llvmRoot := filepath.Dir(filepath.Dir(binpath))
|
|
||||||
clangVersionRoot := filepath.Join(llvmRoot, "lib64", "clang")
|
|
||||||
dirs64, err64 := ioutil.ReadDir(clangVersionRoot)
|
|
||||||
// Example include path:
|
|
||||||
// /usr/lib/llvm-9/lib/clang/9.0.1/include/
|
|
||||||
clangVersionRoot = filepath.Join(llvmRoot, "lib", "clang")
|
|
||||||
dirs32, err32 := ioutil.ReadDir(clangVersionRoot)
|
|
||||||
if err64 != nil && err32 != nil {
|
|
||||||
// Unexpected.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dirnames := make([]string, len(dirs64)+len(dirs32))
|
|
||||||
dirCount := 0
|
|
||||||
for _, d := range dirs32 {
|
|
||||||
name := d.Name()
|
|
||||||
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
|
||||||
dirnames[dirCount] = filepath.Join(llvmRoot, "lib", "clang", name)
|
|
||||||
dirCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, d := range dirs64 {
|
|
||||||
name := d.Name()
|
|
||||||
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
|
||||||
dirnames[dirCount] = filepath.Join(llvmRoot, "lib64", "clang", name)
|
|
||||||
dirCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(dirnames)
|
|
||||||
// Check for the highest version first.
|
|
||||||
for i := dirCount - 1; i >= 0; i-- {
|
|
||||||
path := filepath.Join(dirnames[i], "include")
|
|
||||||
_, err := os.Stat(filepath.Join(path, "stdint.h"))
|
|
||||||
if err == nil {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// On Arch Linux, the clang executable is stored in /usr/bin rather than being symlinked from there.
|
|
||||||
// Search directly in /usr/lib for clang.
|
|
||||||
if matches, err := filepath.Glob("/usr/lib/clang/" + llvmMajor + ".*.*"); err == nil {
|
|
||||||
// Check for the highest version first.
|
|
||||||
sort.Strings(matches)
|
|
||||||
for i := len(matches) - 1; i >= 0; i-- {
|
|
||||||
path := filepath.Join(matches[i], "include")
|
|
||||||
_, err := os.Stat(filepath.Join(path, "stdint.h"))
|
|
||||||
if err == nil {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Could not find it.
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
+4
-6
@@ -143,6 +143,10 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
// reproducible. Otherwise the temporary directory is stored in the archive
|
// reproducible. Otherwise the temporary directory is stored in the archive
|
||||||
// itself, which varies each run.
|
// itself, which varies each run.
|
||||||
args := append(l.cflags(target, headerPath), "-c", "-Oz", "-gdwarf-4", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
|
args := append(l.cflags(target, headerPath), "-c", "-Oz", "-gdwarf-4", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
|
||||||
|
resourceDir := goenv.ClangResourceDir(false)
|
||||||
|
if resourceDir != "" {
|
||||||
|
args = append(args, "-resource-dir="+resourceDir)
|
||||||
|
}
|
||||||
cpu := config.CPU()
|
cpu := config.CPU()
|
||||||
if cpu != "" {
|
if cpu != "" {
|
||||||
// X86 has deprecated the -mcpu flag, so we need to use -march instead.
|
// X86 has deprecated the -mcpu flag, so we need to use -march instead.
|
||||||
@@ -178,12 +182,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
if strings.HasPrefix(target, "riscv64-") {
|
if strings.HasPrefix(target, "riscv64-") {
|
||||||
args = append(args, "-march=rv64gc")
|
args = append(args, "-march=rv64gc")
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(target, "xtensa") {
|
|
||||||
// Hack to work around an issue in the Xtensa port:
|
|
||||||
// https://github.com/espressif/llvm-project/issues/52
|
|
||||||
// Hopefully this will be fixed soon (LLVM 14).
|
|
||||||
args = append(args, "-D__ELF__")
|
|
||||||
}
|
|
||||||
|
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
|
||||||
|
|||||||
+9
-20
@@ -5,7 +5,11 @@
|
|||||||
#include <lld/Common/Driver.h>
|
#include <lld/Common/Driver.h>
|
||||||
#include <llvm/Support/Parallel.h>
|
#include <llvm/Support/Parallel.h>
|
||||||
|
|
||||||
extern "C" {
|
LLD_HAS_DRIVER(coff)
|
||||||
|
LLD_HAS_DRIVER(elf)
|
||||||
|
LLD_HAS_DRIVER(mingw)
|
||||||
|
LLD_HAS_DRIVER(macho)
|
||||||
|
LLD_HAS_DRIVER(wasm)
|
||||||
|
|
||||||
static void configure() {
|
static void configure() {
|
||||||
#if _WIN64
|
#if _WIN64
|
||||||
@@ -16,28 +20,13 @@ static void configure() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tinygo_link_elf(int argc, char **argv) {
|
extern "C" {
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tinygo_link_macho(int argc, char **argv) {
|
bool tinygo_link(int argc, char **argv) {
|
||||||
configure();
|
configure();
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
std::vector<const char*> args(argv, argv + argc);
|
||||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
lld::Result r = lld::lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS);
|
||||||
}
|
return !r.retCode;
|
||||||
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv) {
|
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tinygo_link_wasm(int argc, char **argv) {
|
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // external "C"
|
} // external "C"
|
||||||
|
|||||||
+2
-7
@@ -6,12 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
"tinygo.org/x/go-llvm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Musl = Library{
|
var Musl = Library{
|
||||||
@@ -93,6 +91,7 @@ var Musl = Library{
|
|||||||
"-Wno-string-plus-int",
|
"-Wno-string-plus-int",
|
||||||
"-Wno-ignored-pragmas",
|
"-Wno-ignored-pragmas",
|
||||||
"-Wno-tautological-constant-out-of-range-compare",
|
"-Wno-tautological-constant-out-of-range-compare",
|
||||||
|
"-Wno-deprecated-non-prototype",
|
||||||
"-Qunused-arguments",
|
"-Qunused-arguments",
|
||||||
// Select include dirs. Don't include standard library includes
|
// Select include dirs. Don't include standard library includes
|
||||||
// (that would introduce host dependencies and other complications),
|
// (that would introduce host dependencies and other complications),
|
||||||
@@ -106,11 +105,6 @@ var Musl = Library{
|
|||||||
"-I" + muslDir + "/include",
|
"-I" + muslDir + "/include",
|
||||||
"-fno-stack-protector",
|
"-fno-stack-protector",
|
||||||
}
|
}
|
||||||
llvmMajor, _ := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
|
|
||||||
if llvmMajor >= 15 {
|
|
||||||
// This flag was added in Clang 15. It is not present in LLVM 14.
|
|
||||||
cflags = append(cflags, "-Wno-deprecated-non-prototype")
|
|
||||||
}
|
|
||||||
return cflags
|
return cflags
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
||||||
@@ -125,6 +119,7 @@ var Musl = Library{
|
|||||||
"internal/syscall_ret.c",
|
"internal/syscall_ret.c",
|
||||||
"internal/vdso.c",
|
"internal/vdso.c",
|
||||||
"legacy/*.c",
|
"legacy/*.c",
|
||||||
|
"linux/*.c",
|
||||||
"malloc/*.c",
|
"malloc/*.c",
|
||||||
"malloc/mallocng/*.c",
|
"malloc/mallocng/*.c",
|
||||||
"mman/*.c",
|
"mman/*.c",
|
||||||
|
|||||||
+99
-79
@@ -3,6 +3,7 @@ package builder
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
@@ -41,91 +42,23 @@ var Picolibc = Library{
|
|||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string) ([]string, error) {
|
||||||
return picolibcSources, nil
|
sources := append([]string(nil), picolibcSources...)
|
||||||
|
if !strings.HasPrefix(target, "avr") {
|
||||||
|
// Small chips without long jumps can't compile many files (printf,
|
||||||
|
// pow, etc). Therefore exclude those source files for those chips.
|
||||||
|
// Unfortunately it's difficult to exclude only some chips, so this
|
||||||
|
// excludes those files on all AVR chips for now.
|
||||||
|
// More information:
|
||||||
|
// https://github.com/llvm/llvm-project/issues/67042
|
||||||
|
sources = append(sources, picolibcSourcesLarge...)
|
||||||
|
}
|
||||||
|
return sources, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var picolibcSources = []string{
|
var picolibcSources = []string{
|
||||||
"../../picolibc-stdio.c",
|
"../../picolibc-stdio.c",
|
||||||
|
|
||||||
// srcs_tinystdio
|
|
||||||
"libc/tinystdio/asprintf.c",
|
|
||||||
"libc/tinystdio/bufio.c",
|
|
||||||
"libc/tinystdio/clearerr.c",
|
|
||||||
"libc/tinystdio/ecvt_r.c",
|
|
||||||
"libc/tinystdio/ecvt.c",
|
|
||||||
"libc/tinystdio/ecvtf_r.c",
|
|
||||||
"libc/tinystdio/ecvtf.c",
|
|
||||||
"libc/tinystdio/fcvt.c",
|
|
||||||
"libc/tinystdio/fcvt_r.c",
|
|
||||||
"libc/tinystdio/fcvtf.c",
|
|
||||||
"libc/tinystdio/fcvtf_r.c",
|
|
||||||
"libc/tinystdio/gcvt.c",
|
|
||||||
"libc/tinystdio/gcvtf.c",
|
|
||||||
"libc/tinystdio/fclose.c",
|
|
||||||
"libc/tinystdio/fdevopen.c",
|
|
||||||
"libc/tinystdio/feof.c",
|
|
||||||
"libc/tinystdio/ferror.c",
|
|
||||||
"libc/tinystdio/fflush.c",
|
|
||||||
"libc/tinystdio/fgetc.c",
|
|
||||||
"libc/tinystdio/fgets.c",
|
|
||||||
"libc/tinystdio/fileno.c",
|
|
||||||
"libc/tinystdio/filestrget.c",
|
|
||||||
"libc/tinystdio/filestrput.c",
|
|
||||||
"libc/tinystdio/filestrputalloc.c",
|
|
||||||
"libc/tinystdio/fmemopen.c",
|
|
||||||
"libc/tinystdio/fprintf.c",
|
|
||||||
"libc/tinystdio/fputc.c",
|
|
||||||
"libc/tinystdio/fputs.c",
|
|
||||||
"libc/tinystdio/fread.c",
|
|
||||||
//"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369
|
|
||||||
"libc/tinystdio/fscanf.c",
|
|
||||||
"libc/tinystdio/fseek.c",
|
|
||||||
"libc/tinystdio/fseeko.c",
|
|
||||||
"libc/tinystdio/ftell.c",
|
|
||||||
"libc/tinystdio/ftello.c",
|
|
||||||
"libc/tinystdio/fwrite.c",
|
|
||||||
"libc/tinystdio/getchar.c",
|
|
||||||
"libc/tinystdio/gets.c",
|
|
||||||
"libc/tinystdio/matchcaseprefix.c",
|
|
||||||
"libc/tinystdio/mktemp.c",
|
|
||||||
"libc/tinystdio/perror.c",
|
|
||||||
"libc/tinystdio/printf.c",
|
|
||||||
"libc/tinystdio/putchar.c",
|
|
||||||
"libc/tinystdio/puts.c",
|
|
||||||
"libc/tinystdio/rewind.c",
|
|
||||||
"libc/tinystdio/scanf.c",
|
|
||||||
"libc/tinystdio/setbuf.c",
|
|
||||||
"libc/tinystdio/setbuffer.c",
|
|
||||||
"libc/tinystdio/setlinebuf.c",
|
|
||||||
"libc/tinystdio/setvbuf.c",
|
|
||||||
"libc/tinystdio/snprintf.c",
|
|
||||||
"libc/tinystdio/sprintf.c",
|
|
||||||
"libc/tinystdio/snprintfd.c",
|
|
||||||
"libc/tinystdio/snprintff.c",
|
|
||||||
"libc/tinystdio/sprintff.c",
|
|
||||||
"libc/tinystdio/sprintfd.c",
|
|
||||||
"libc/tinystdio/sscanf.c",
|
|
||||||
"libc/tinystdio/strfromf.c",
|
|
||||||
"libc/tinystdio/strfromd.c",
|
|
||||||
"libc/tinystdio/strtof.c",
|
|
||||||
"libc/tinystdio/strtof_l.c",
|
|
||||||
"libc/tinystdio/strtod.c",
|
|
||||||
"libc/tinystdio/strtod_l.c",
|
|
||||||
"libc/tinystdio/ungetc.c",
|
|
||||||
"libc/tinystdio/vasprintf.c",
|
|
||||||
"libc/tinystdio/vfiprintf.c",
|
|
||||||
"libc/tinystdio/vfprintf.c",
|
|
||||||
"libc/tinystdio/vfprintff.c",
|
|
||||||
"libc/tinystdio/vfscanf.c",
|
|
||||||
"libc/tinystdio/vfiscanf.c",
|
|
||||||
"libc/tinystdio/vfscanff.c",
|
|
||||||
"libc/tinystdio/vprintf.c",
|
|
||||||
"libc/tinystdio/vscanf.c",
|
|
||||||
"libc/tinystdio/vsscanf.c",
|
|
||||||
"libc/tinystdio/vsnprintf.c",
|
|
||||||
"libc/tinystdio/vsprintf.c",
|
|
||||||
|
|
||||||
"libc/string/bcmp.c",
|
"libc/string/bcmp.c",
|
||||||
"libc/string/bcopy.c",
|
"libc/string/bcopy.c",
|
||||||
"libc/string/bzero.c",
|
"libc/string/bzero.c",
|
||||||
@@ -229,6 +162,87 @@ var picolibcSources = []string{
|
|||||||
"libc/string/wmempcpy.c",
|
"libc/string/wmempcpy.c",
|
||||||
"libc/string/wmemset.c",
|
"libc/string/wmemset.c",
|
||||||
"libc/string/xpg_strerror_r.c",
|
"libc/string/xpg_strerror_r.c",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parts of picolibc that are too large for small AVRs.
|
||||||
|
var picolibcSourcesLarge = []string{
|
||||||
|
// srcs_tinystdio
|
||||||
|
"libc/tinystdio/asprintf.c",
|
||||||
|
"libc/tinystdio/bufio.c",
|
||||||
|
"libc/tinystdio/clearerr.c",
|
||||||
|
"libc/tinystdio/ecvt_r.c",
|
||||||
|
"libc/tinystdio/ecvt.c",
|
||||||
|
"libc/tinystdio/ecvtf_r.c",
|
||||||
|
"libc/tinystdio/ecvtf.c",
|
||||||
|
"libc/tinystdio/fcvt.c",
|
||||||
|
"libc/tinystdio/fcvt_r.c",
|
||||||
|
"libc/tinystdio/fcvtf.c",
|
||||||
|
"libc/tinystdio/fcvtf_r.c",
|
||||||
|
"libc/tinystdio/gcvt.c",
|
||||||
|
"libc/tinystdio/gcvtf.c",
|
||||||
|
"libc/tinystdio/fclose.c",
|
||||||
|
"libc/tinystdio/fdevopen.c",
|
||||||
|
"libc/tinystdio/feof.c",
|
||||||
|
"libc/tinystdio/ferror.c",
|
||||||
|
"libc/tinystdio/fflush.c",
|
||||||
|
"libc/tinystdio/fgetc.c",
|
||||||
|
"libc/tinystdio/fgets.c",
|
||||||
|
"libc/tinystdio/fileno.c",
|
||||||
|
"libc/tinystdio/filestrget.c",
|
||||||
|
"libc/tinystdio/filestrput.c",
|
||||||
|
"libc/tinystdio/filestrputalloc.c",
|
||||||
|
"libc/tinystdio/fmemopen.c",
|
||||||
|
"libc/tinystdio/fprintf.c",
|
||||||
|
"libc/tinystdio/fputc.c",
|
||||||
|
"libc/tinystdio/fputs.c",
|
||||||
|
"libc/tinystdio/fread.c",
|
||||||
|
//"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369
|
||||||
|
"libc/tinystdio/fscanf.c",
|
||||||
|
"libc/tinystdio/fseek.c",
|
||||||
|
"libc/tinystdio/fseeko.c",
|
||||||
|
"libc/tinystdio/ftell.c",
|
||||||
|
"libc/tinystdio/ftello.c",
|
||||||
|
"libc/tinystdio/fwrite.c",
|
||||||
|
"libc/tinystdio/getchar.c",
|
||||||
|
"libc/tinystdio/gets.c",
|
||||||
|
"libc/tinystdio/matchcaseprefix.c",
|
||||||
|
"libc/tinystdio/mktemp.c",
|
||||||
|
"libc/tinystdio/perror.c",
|
||||||
|
"libc/tinystdio/printf.c",
|
||||||
|
"libc/tinystdio/putchar.c",
|
||||||
|
"libc/tinystdio/puts.c",
|
||||||
|
"libc/tinystdio/rewind.c",
|
||||||
|
"libc/tinystdio/scanf.c",
|
||||||
|
"libc/tinystdio/setbuf.c",
|
||||||
|
"libc/tinystdio/setbuffer.c",
|
||||||
|
"libc/tinystdio/setlinebuf.c",
|
||||||
|
"libc/tinystdio/setvbuf.c",
|
||||||
|
"libc/tinystdio/snprintf.c",
|
||||||
|
"libc/tinystdio/sprintf.c",
|
||||||
|
"libc/tinystdio/snprintfd.c",
|
||||||
|
"libc/tinystdio/snprintff.c",
|
||||||
|
"libc/tinystdio/sprintff.c",
|
||||||
|
"libc/tinystdio/sprintfd.c",
|
||||||
|
"libc/tinystdio/sscanf.c",
|
||||||
|
"libc/tinystdio/strfromf.c",
|
||||||
|
"libc/tinystdio/strfromd.c",
|
||||||
|
"libc/tinystdio/strtof.c",
|
||||||
|
"libc/tinystdio/strtof_l.c",
|
||||||
|
"libc/tinystdio/strtod.c",
|
||||||
|
"libc/tinystdio/strtod_l.c",
|
||||||
|
"libc/tinystdio/ungetc.c",
|
||||||
|
"libc/tinystdio/vasprintf.c",
|
||||||
|
"libc/tinystdio/vfiprintf.c",
|
||||||
|
"libc/tinystdio/vfprintf.c",
|
||||||
|
"libc/tinystdio/vfprintff.c",
|
||||||
|
"libc/tinystdio/vfscanf.c",
|
||||||
|
"libc/tinystdio/vfiscanf.c",
|
||||||
|
"libc/tinystdio/vfscanff.c",
|
||||||
|
"libc/tinystdio/vprintf.c",
|
||||||
|
"libc/tinystdio/vscanf.c",
|
||||||
|
"libc/tinystdio/vsscanf.c",
|
||||||
|
"libc/tinystdio/vsnprintf.c",
|
||||||
|
"libc/tinystdio/vsprintf.c",
|
||||||
|
|
||||||
"libm/common/sf_finite.c",
|
"libm/common/sf_finite.c",
|
||||||
"libm/common/sf_copysign.c",
|
"libm/common/sf_copysign.c",
|
||||||
@@ -323,6 +337,12 @@ var picolibcSources = []string{
|
|||||||
"libm/common/math_err_may_uflow.c",
|
"libm/common/math_err_may_uflow.c",
|
||||||
"libm/common/math_err_check_uflow.c",
|
"libm/common/math_err_check_uflow.c",
|
||||||
"libm/common/math_err_check_oflow.c",
|
"libm/common/math_err_check_oflow.c",
|
||||||
|
"libm/common/math_errf_divzerof.c",
|
||||||
|
"libm/common/math_errf_invalidf.c",
|
||||||
|
"libm/common/math_errf_may_uflowf.c",
|
||||||
|
"libm/common/math_errf_oflowf.c",
|
||||||
|
"libm/common/math_errf_uflowf.c",
|
||||||
|
"libm/common/math_errf_with_errnof.c",
|
||||||
"libm/common/math_inexact.c",
|
"libm/common/math_inexact.c",
|
||||||
"libm/common/math_inexactf.c",
|
"libm/common/math_inexactf.c",
|
||||||
"libm/common/log.c",
|
"libm/common/log.c",
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ func TestBinarySize(t *testing.T) {
|
|||||||
// This is a small number of very diverse targets that we want to test.
|
// This is a small number of very diverse targets that we want to test.
|
||||||
tests := []sizeTest{
|
tests := []sizeTest{
|
||||||
// microcontrollers
|
// microcontrollers
|
||||||
{"hifive1b", "examples/echo", 4568, 280, 0, 2252},
|
{"hifive1b", "examples/echo", 4484, 280, 0, 2252},
|
||||||
{"microbit", "examples/serial", 2728, 388, 8, 2256},
|
{"microbit", "examples/serial", 2732, 388, 8, 2256},
|
||||||
{"wioterminal", "examples/pininterrupt", 5996, 1484, 116, 6816},
|
{"wioterminal", "examples/pininterrupt", 6016, 1484, 116, 6816},
|
||||||
|
|
||||||
// TODO: also check wasm. Right now this is difficult, because
|
// TODO: also check wasm. Right now this is difficult, because
|
||||||
// wasm binaries are run through wasm-opt and therefore the
|
// wasm binaries are run through wasm-opt and therefore the
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ import (
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
bool tinygo_clang_driver(int argc, char **argv);
|
bool tinygo_clang_driver(int argc, char **argv);
|
||||||
bool tinygo_link_elf(int argc, char **argv);
|
bool tinygo_link(int argc, char **argv);
|
||||||
bool tinygo_link_macho(int argc, char **argv);
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv);
|
|
||||||
bool tinygo_link_wasm(int argc, char **argv);
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
@@ -26,16 +23,7 @@ const hasBuiltinTools = true
|
|||||||
// This version actually runs the tools because TinyGo was compiled while
|
// This version actually runs the tools because TinyGo was compiled while
|
||||||
// linking statically with LLVM (with the byollvm build tag).
|
// linking statically with LLVM (with the byollvm build tag).
|
||||||
func RunTool(tool string, args ...string) error {
|
func RunTool(tool string, args ...string) error {
|
||||||
linker := "elf"
|
args = append([]string{tool}, args...)
|
||||||
if tool == "ld.lld" && len(args) >= 2 {
|
|
||||||
if args[0] == "-m" && (args[1] == "i386pep" || args[1] == "arm64pe") {
|
|
||||||
linker = "mingw"
|
|
||||||
} else if args[0] == "-flavor" {
|
|
||||||
linker = args[1]
|
|
||||||
args = args[2:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args = append([]string{"tinygo:" + tool}, args...)
|
|
||||||
|
|
||||||
var cflag *C.char
|
var cflag *C.char
|
||||||
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
||||||
@@ -51,19 +39,8 @@ func RunTool(tool string, args ...string) error {
|
|||||||
switch tool {
|
switch tool {
|
||||||
case "clang":
|
case "clang":
|
||||||
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
||||||
case "ld.lld":
|
case "ld.lld", "wasm-ld":
|
||||||
switch linker {
|
ok = C.tinygo_link(C.int(len(args)), (**C.char)(buf))
|
||||||
case "darwin":
|
|
||||||
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
|
|
||||||
case "elf":
|
|
||||||
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
|
|
||||||
case "mingw":
|
|
||||||
ok = C.tinygo_link_mingw(C.int(len(args)), (**C.char)(buf))
|
|
||||||
default:
|
|
||||||
return errors.New("unknown linker: " + linker)
|
|
||||||
}
|
|
||||||
case "wasm-ld":
|
|
||||||
ok = C.tinygo_link_wasm(C.int(len(args)), (**C.char)(buf))
|
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown tool: " + tool)
|
return errors.New("unknown tool: " + tool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
@@ -12,11 +11,6 @@ import (
|
|||||||
func runCCompiler(flags ...string) error {
|
func runCCompiler(flags ...string) error {
|
||||||
if hasBuiltinTools {
|
if hasBuiltinTools {
|
||||||
// Compile this with the internal Clang compiler.
|
// Compile this with the internal Clang compiler.
|
||||||
headerPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
|
||||||
if headerPath == "" {
|
|
||||||
return errors.New("could not locate Clang headers")
|
|
||||||
}
|
|
||||||
flags = append(flags, "-I"+headerPath)
|
|
||||||
cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
|
cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var WasmBuiltins = Library{
|
||||||
|
name: "wasmbuiltins",
|
||||||
|
makeHeaders: func(target, includeDir string) error {
|
||||||
|
if err := os.Mkdir(includeDir+"/bits", 0o777); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Create(includeDir + "/bits/alltypes.h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := f.Write([]byte(wasmAllTypes)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return f.Close()
|
||||||
|
},
|
||||||
|
cflags: func(target, headerPath string) []string {
|
||||||
|
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
|
||||||
|
return []string{
|
||||||
|
"-Werror",
|
||||||
|
"-Wall",
|
||||||
|
"-std=gnu11",
|
||||||
|
"-nostdlibinc",
|
||||||
|
"-isystem", libcDir + "/libc-top-half/musl/arch/wasm32",
|
||||||
|
"-isystem", libcDir + "/libc-top-half/musl/arch/generic",
|
||||||
|
"-isystem", libcDir + "/libc-top-half/musl/src/internal",
|
||||||
|
"-isystem", libcDir + "/libc-top-half/musl/src/include",
|
||||||
|
"-isystem", libcDir + "/libc-top-half/musl/include",
|
||||||
|
"-isystem", libcDir + "/libc-bottom-half/headers/public",
|
||||||
|
"-I" + headerPath,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
||||||
|
librarySources: func(target string) ([]string, error) {
|
||||||
|
return []string{
|
||||||
|
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
|
||||||
|
// llvm.memset.* LLVM intrinsics.
|
||||||
|
"libc-top-half/musl/src/string/memcpy.c",
|
||||||
|
"libc-top-half/musl/src/string/memmove.c",
|
||||||
|
"libc-top-half/musl/src/string/memset.c",
|
||||||
|
|
||||||
|
// exp, exp2, and log are needed for LLVM math builtin functions
|
||||||
|
// like llvm.exp.*.
|
||||||
|
"libc-top-half/musl/src/math/__math_divzero.c",
|
||||||
|
"libc-top-half/musl/src/math/__math_invalid.c",
|
||||||
|
"libc-top-half/musl/src/math/__math_oflow.c",
|
||||||
|
"libc-top-half/musl/src/math/__math_uflow.c",
|
||||||
|
"libc-top-half/musl/src/math/__math_xflow.c",
|
||||||
|
"libc-top-half/musl/src/math/exp.c",
|
||||||
|
"libc-top-half/musl/src/math/exp_data.c",
|
||||||
|
"libc-top-half/musl/src/math/exp2.c",
|
||||||
|
"libc-top-half/musl/src/math/log.c",
|
||||||
|
"libc-top-half/musl/src/math/log_data.c",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// alltypes.h for wasm-libc, using the types as defined inside Clang.
|
||||||
|
const wasmAllTypes = `
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __INT8_TYPE__ int8_t;
|
||||||
|
typedef __INT16_TYPE__ int16_t;
|
||||||
|
typedef __INT32_TYPE__ int32_t;
|
||||||
|
typedef __INT64_TYPE__ int64_t;
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
|
||||||
|
// This type is used internally in wasi-libc.
|
||||||
|
typedef double double_t;
|
||||||
|
`
|
||||||
+14
-7
@@ -25,9 +25,15 @@ import (
|
|||||||
"golang.org/x/tools/go/ast/astutil"
|
"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.
|
// cgoPackage holds all CGo-related information of a package.
|
||||||
type cgoPackage struct {
|
type cgoPackage struct {
|
||||||
generated *ast.File
|
generated *ast.File
|
||||||
|
packageName string
|
||||||
|
cgoFiles []*ast.File
|
||||||
generatedPos token.Pos
|
generatedPos token.Pos
|
||||||
errors []error
|
errors []error
|
||||||
currentDir string // current working directory
|
currentDir string // current working directory
|
||||||
@@ -88,6 +94,7 @@ var cgoAliases = map[string]string{
|
|||||||
"C.uintptr_t": "uintptr",
|
"C.uintptr_t": "uintptr",
|
||||||
"C.float": "float32",
|
"C.float": "float32",
|
||||||
"C.double": "float64",
|
"C.double": "float64",
|
||||||
|
"C._Bool": "bool",
|
||||||
}
|
}
|
||||||
|
|
||||||
// builtinAliases are handled specially because they only exist on the Go side
|
// builtinAliases are handled specially because they only exist on the Go side
|
||||||
@@ -164,8 +171,9 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
||||||
// hashes of the accessed C header files. If there is one or more error, it
|
// hashes of the accessed C header files. If there is one or more error, it
|
||||||
// returns these in the []error slice but still modifies the AST.
|
// returns these in the []error slice but still modifies the AST.
|
||||||
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string) ([]*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||||
p := &cgoPackage{
|
p := &cgoPackage{
|
||||||
|
packageName: files[0].Name.Name,
|
||||||
currentDir: dir,
|
currentDir: dir,
|
||||||
importPath: importPath,
|
importPath: importPath,
|
||||||
fset: fset,
|
fset: fset,
|
||||||
@@ -201,6 +209,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// This is always a bug in the cgo package.
|
// This is always a bug in the cgo package.
|
||||||
panic("unexpected error: " + err.Error())
|
panic("unexpected error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
p.cgoFiles = append(p.cgoFiles, p.generated)
|
||||||
// If the Comments field is not set to nil, the go/format package will get
|
// If the Comments field is not set to nil, the go/format package will get
|
||||||
// confused about where comments should go.
|
// confused about where comments should go.
|
||||||
p.generated.Comments = nil
|
p.generated.Comments = nil
|
||||||
@@ -291,9 +300,6 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// have better alternatives anyway.
|
// have better alternatives anyway.
|
||||||
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
|
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
|
||||||
cflagsForCGo = append(cflagsForCGo, p.cflags...)
|
cflagsForCGo = append(cflagsForCGo, p.cflags...)
|
||||||
if clangHeaders != "" {
|
|
||||||
cflagsForCGo = append(cflagsForCGo, "-isystem", clangHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve types such as C.int, C.longlong, etc from C.
|
// Retrieve types such as C.int, C.longlong, etc from C.
|
||||||
p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
||||||
@@ -311,10 +317,11 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// Process CGo imports for each file.
|
// Process CGo imports for each file.
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
cf := p.newCGoFile(f, i)
|
cf := p.newCGoFile(f, i)
|
||||||
// Float and double are aliased, meaning that C.float is the same thing
|
// These types are aliased with the corresponding types in C. For
|
||||||
// as float32 in Go.
|
// example, float in C is always float32 in Go.
|
||||||
cf.names["float"] = clangCursor{}
|
cf.names["float"] = clangCursor{}
|
||||||
cf.names["double"] = clangCursor{}
|
cf.names["double"] = clangCursor{}
|
||||||
|
cf.names["_Bool"] = clangCursor{}
|
||||||
// Now read all the names (identifies) that C defines in the header
|
// Now read all the names (identifies) that C defines in the header
|
||||||
// snippet.
|
// snippet.
|
||||||
cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
||||||
@@ -333,7 +340,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// Print the newly generated in-memory AST, for debugging.
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
//ast.Print(fset, p.generated)
|
//ast.Print(fset, p.generated)
|
||||||
|
|
||||||
return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
return p.cgoFiles, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -55,7 +55,7 @@ func TestCGo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process the AST with CGo.
|
// Process the AST with CGo.
|
||||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags, "")
|
cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
|
||||||
|
|
||||||
// Check the AST for type errors.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
var typecheckErrors []error
|
||||||
@@ -66,7 +66,7 @@ func TestCGo(t *testing.T) {
|
|||||||
Importer: simpleImporter{},
|
Importer: simpleImporter{},
|
||||||
Sizes: types.SizesFor("gccgo", "arm"),
|
Sizes: types.SizesFor("gccgo", "arm"),
|
||||||
}
|
}
|
||||||
_, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil)
|
_, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil)
|
||||||
if err != nil && len(typecheckErrors) == 0 {
|
if err != nil && len(typecheckErrors) == 0 {
|
||||||
// Only report errors when no type errors are found (an
|
// Only report errors when no type errors are found (an
|
||||||
// unexpected condition).
|
// unexpected condition).
|
||||||
@@ -91,7 +91,7 @@ func TestCGo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
buf.WriteString("\n")
|
buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
err = format.Node(buf, fset, cgoAST)
|
err = format.Node(buf, fset, cgoFiles[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not write out CGo AST: %v", err)
|
t.Errorf("could not write out CGo AST: %v", err)
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ func (i simpleImporter) Import(path string) (*types.Package, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatDiagnostics formats the error message to be an indented comment. It
|
// formatDiagnostic formats the error message to be an indented comment. It
|
||||||
// also fixes Windows path name issues (backward slashes).
|
// also fixes Windows path name issues (backward slashes).
|
||||||
func formatDiagnostic(err error) string {
|
func formatDiagnostic(err error) string {
|
||||||
msg := err.Error()
|
msg := err.Error()
|
||||||
|
|||||||
+12
-2
@@ -17,6 +17,8 @@ var (
|
|||||||
token.OR: precedenceOr,
|
token.OR: precedenceOr,
|
||||||
token.XOR: precedenceXor,
|
token.XOR: precedenceXor,
|
||||||
token.AND: precedenceAnd,
|
token.AND: precedenceAnd,
|
||||||
|
token.SHL: precedenceShift,
|
||||||
|
token.SHR: precedenceShift,
|
||||||
token.ADD: precedenceAdd,
|
token.ADD: precedenceAdd,
|
||||||
token.SUB: precedenceAdd,
|
token.SUB: precedenceAdd,
|
||||||
token.MUL: precedenceMul,
|
token.MUL: precedenceMul,
|
||||||
@@ -25,11 +27,13 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// See: https://en.cppreference.com/w/c/language/operator_precedence
|
||||||
const (
|
const (
|
||||||
precedenceLowest = iota + 1
|
precedenceLowest = iota + 1
|
||||||
precedenceOr
|
precedenceOr
|
||||||
precedenceXor
|
precedenceXor
|
||||||
precedenceAnd
|
precedenceAnd
|
||||||
|
precedenceShift
|
||||||
precedenceAdd
|
precedenceAdd
|
||||||
precedenceMul
|
precedenceMul
|
||||||
precedencePrefix
|
precedencePrefix
|
||||||
@@ -82,7 +86,7 @@ func parseConstExpr(t *tokenizer, precedence int) (ast.Expr, *scanner.Error) {
|
|||||||
|
|
||||||
for t.peekToken != token.EOF && precedence < precedences[t.peekToken] {
|
for t.peekToken != token.EOF && precedence < precedences[t.peekToken] {
|
||||||
switch t.peekToken {
|
switch t.peekToken {
|
||||||
case token.OR, token.XOR, token.AND, token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
|
case token.OR, token.XOR, token.AND, token.SHL, token.SHR, token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
|
||||||
t.Next()
|
t.Next()
|
||||||
leftExpr, err = parseBinaryExpr(t, leftExpr)
|
leftExpr, err = parseBinaryExpr(t, leftExpr)
|
||||||
}
|
}
|
||||||
@@ -205,13 +209,19 @@ func (t *tokenizer) Next() {
|
|||||||
// https://en.cppreference.com/w/cpp/string/byte/isspace
|
// https://en.cppreference.com/w/cpp/string/byte/isspace
|
||||||
t.peekPos++
|
t.peekPos++
|
||||||
t.buf = t.buf[1:]
|
t.buf = t.buf[1:]
|
||||||
case len(t.buf) >= 2 && (string(t.buf[:2]) == "||" || string(t.buf[:2]) == "&&"):
|
case len(t.buf) >= 2 && (string(t.buf[:2]) == "||" || string(t.buf[:2]) == "&&" || string(t.buf[:2]) == "<<" || string(t.buf[:2]) == ">>"):
|
||||||
// Two-character tokens.
|
// Two-character tokens.
|
||||||
switch c {
|
switch c {
|
||||||
case '&':
|
case '&':
|
||||||
t.peekToken = token.LAND
|
t.peekToken = token.LAND
|
||||||
case '|':
|
case '|':
|
||||||
t.peekToken = token.LOR
|
t.peekToken = token.LOR
|
||||||
|
case '<':
|
||||||
|
t.peekToken = token.SHL
|
||||||
|
case '>':
|
||||||
|
t.peekToken = token.SHR
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
t.peekValue = t.buf[:2]
|
t.peekValue = t.buf[:2]
|
||||||
t.buf = t.buf[2:]
|
t.buf = t.buf[2:]
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ func TestParseConst(t *testing.T) {
|
|||||||
{`5&5`, `5 & 5`},
|
{`5&5`, `5 & 5`},
|
||||||
{`5|5`, `5 | 5`},
|
{`5|5`, `5 | 5`},
|
||||||
{`5^5`, `5 ^ 5`},
|
{`5^5`, `5 ^ 5`},
|
||||||
|
{`5<<5`, `5 << 5`},
|
||||||
|
{`5>>5`, `5 >> 5`},
|
||||||
|
{`5>>5 + 3`, `5 >> (5 + 3)`},
|
||||||
|
{`5>>5 ^ 3`, `5>>5 ^ 3`},
|
||||||
{`5||5`, `error: 1:2: unexpected token ||, expected end of expression`}, // logical binops aren't supported yet
|
{`5||5`, `error: 1:2: unexpected token ||, expected end of expression`}, // logical binops aren't supported yet
|
||||||
{`(5/5)`, `(5 / 5)`},
|
{`(5/5)`, `(5 / 5)`},
|
||||||
{`1 - 2`, `1 - 2`},
|
{`1 - 2`, `1 - 2`},
|
||||||
|
|||||||
@@ -589,6 +589,13 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
|
|||||||
f := p.fset.AddFile(filename, -1, int(size))
|
f := p.fset.AddFile(filename, -1, int(size))
|
||||||
f.SetLines(lines)
|
f.SetLines(lines)
|
||||||
p.tokenFiles[filename] = f
|
p.tokenFiles[filename] = f
|
||||||
|
// Add dummy file AST, to satisfy the type checker.
|
||||||
|
astFile := &ast.File{
|
||||||
|
Package: f.Pos(0),
|
||||||
|
Name: ast.NewIdent(p.packageName),
|
||||||
|
}
|
||||||
|
setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
|
||||||
|
p.cgoFiles = append(p.cgoFiles, astFile)
|
||||||
}
|
}
|
||||||
positionFile := p.tokenFiles[filename]
|
positionFile := p.tokenFiles[filename]
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
//go:build !byollvm && llvm14
|
|
||||||
|
|
||||||
package cgo
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo linux CFLAGS: -I/usr/lib/llvm-14/include
|
|
||||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@14/include
|
|
||||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@14/include
|
|
||||||
#cgo freebsd CFLAGS: -I/usr/local/llvm14/include
|
|
||||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-14/lib -lclang
|
|
||||||
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@14/lib -lclang -lffi
|
|
||||||
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@14/lib -lclang -lffi
|
|
||||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm14/lib -lclang
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
@@ -8,8 +8,8 @@ package cgo
|
|||||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include
|
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include
|
||||||
#cgo freebsd CFLAGS: -I/usr/local/llvm15/include
|
#cgo freebsd CFLAGS: -I/usr/local/llvm15/include
|
||||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang
|
||||||
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang -lffi
|
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang
|
||||||
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang -lffi
|
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang
|
||||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//go:build !byollvm && !llvm14 && !llvm15
|
//go:build !byollvm && llvm16
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
// As of 2023-05-05, there is a packaging issue on Debian:
|
// As of 2023-05-05, there is a packaging issue with LLVM 16 on Debian:
|
||||||
// https://github.com/llvm/llvm-project/issues/62199
|
// https://github.com/llvm/llvm-project/issues/62199
|
||||||
// A workaround is to fix this locally, using something like this:
|
// A workaround is to fix this locally, using something like this:
|
||||||
//
|
//
|
||||||
@@ -14,8 +14,8 @@ package cgo
|
|||||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
|
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
|
||||||
#cgo freebsd CFLAGS: -I/usr/local/llvm16/include
|
#cgo freebsd CFLAGS: -I/usr/local/llvm16/include
|
||||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
|
||||||
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang -lffi
|
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang
|
||||||
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang -lffi
|
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang
|
||||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//go:build !byollvm && llvm17
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux CFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -I/usr/lib/llvm-17/include
|
||||||
|
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@17/include
|
||||||
|
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@17/include
|
||||||
|
#cgo freebsd CFLAGS: -I/usr/local/llvm17/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-17/lib -lclang
|
||||||
|
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@17/lib -lclang
|
||||||
|
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@17/lib -lclang
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm17/lib -lclang
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux CFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -I/usr/lib/llvm-18/include
|
||||||
|
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@18/include
|
||||||
|
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@18/include
|
||||||
|
#cgo freebsd CFLAGS: -I/usr/local/llvm18/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-18/lib -lclang
|
||||||
|
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@18/lib -lclang
|
||||||
|
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@18/lib -lclang
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm18/lib -lclang
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
+47
-23
@@ -19,7 +19,6 @@ type Config struct {
|
|||||||
Options *Options
|
Options *Options
|
||||||
Target *TargetSpec
|
Target *TargetSpec
|
||||||
GoMinorVersion int
|
GoMinorVersion int
|
||||||
ClangHeaders string // Clang built-in header include path
|
|
||||||
TestConfig TestConfig
|
TestConfig TestConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +74,13 @@ func (c *Config) GOARM() string {
|
|||||||
|
|
||||||
// BuildTags returns the complete list of build tags used during this build.
|
// BuildTags returns the complete list of build tags used during this build.
|
||||||
func (c *Config) BuildTags() []string {
|
func (c *Config) BuildTags() []string {
|
||||||
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race)
|
||||||
|
tags = append(tags, []string{
|
||||||
|
"tinygo", // that's the compiler
|
||||||
|
"purego", // to get various crypto packages to work
|
||||||
|
"math_big_pure_go", // to get math/big to work
|
||||||
|
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
|
||||||
|
"serial." + c.Serial()}...) // used inside the machine package
|
||||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||||
}
|
}
|
||||||
@@ -83,12 +88,6 @@ func (c *Config) BuildTags() []string {
|
|||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
// CgoEnabled returns true if (and only if) CGo is enabled. It is true by
|
|
||||||
// default and false if CGO_ENABLED is set to "0".
|
|
||||||
func (c *Config) CgoEnabled() bool {
|
|
||||||
return goenv.Get("CGO_ENABLED") == "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// GC returns the garbage collection strategy in use on this platform. Valid
|
// GC returns the garbage collection strategy in use on this platform. Valid
|
||||||
// values are "none", "leaking", "conservative" and "precise".
|
// values are "none", "leaking", "conservative" and "precise".
|
||||||
func (c *Config) GC() string {
|
func (c *Config) GC() string {
|
||||||
@@ -145,18 +144,18 @@ func (c *Config) Serial() string {
|
|||||||
|
|
||||||
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
|
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
|
||||||
// threshold as used in the LLVM optimization pipeline.
|
// threshold as used in the LLVM optimization pipeline.
|
||||||
func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
|
func (c *Config) OptLevel() (level string, speedLevel, sizeLevel int) {
|
||||||
switch c.Options.Opt {
|
switch c.Options.Opt {
|
||||||
case "none", "0":
|
case "none", "0":
|
||||||
return 0, 0, 0 // -O0
|
return "O0", 0, 0
|
||||||
case "1":
|
case "1":
|
||||||
return 1, 0, 0 // -O1
|
return "O1", 1, 0
|
||||||
case "2":
|
case "2":
|
||||||
return 2, 0, 225 // -O2
|
return "O2", 2, 0
|
||||||
case "s":
|
case "s":
|
||||||
return 2, 1, 225 // -Os
|
return "Os", 2, 1
|
||||||
case "z":
|
case "z":
|
||||||
return 2, 2, 5 // -Oz, default
|
return "Oz", 2, 2 // default
|
||||||
default:
|
default:
|
||||||
// This is not shown to the user: valid choices are already checked as
|
// This is not shown to the user: valid choices are already checked as
|
||||||
// part of Options.Verify(). It is here as a sanity check.
|
// part of Options.Verify(). It is here as a sanity check.
|
||||||
@@ -190,6 +189,15 @@ func (c *Config) StackSize() uint64 {
|
|||||||
return c.Target.DefaultStackSize
|
return c.Target.DefaultStackSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
return 256
|
||||||
|
}
|
||||||
|
|
||||||
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
|
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
|
||||||
// calculates and patches in the checksum for the 2nd stage bootloader.
|
// calculates and patches in the checksum for the 2nd stage bootloader.
|
||||||
func (c *Config) RP2040BootPatch() bool {
|
func (c *Config) RP2040BootPatch() bool {
|
||||||
@@ -259,24 +267,35 @@ func (c *Config) DefaultBinaryExtension() string {
|
|||||||
|
|
||||||
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
|
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
|
||||||
// preprocessing.
|
// preprocessing.
|
||||||
func (c *Config) CFlags() []string {
|
func (c *Config) CFlags(libclang bool) []string {
|
||||||
var cflags []string
|
var cflags []string
|
||||||
for _, flag := range c.Target.CFlags {
|
for _, flag := range c.Target.CFlags {
|
||||||
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
|
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
|
||||||
}
|
}
|
||||||
|
resourceDir := goenv.ClangResourceDir(libclang)
|
||||||
|
if resourceDir != "" {
|
||||||
|
// The resource directory contains the built-in clang headers like
|
||||||
|
// stdbool.h, stdint.h, float.h, etc.
|
||||||
|
// It is left empty if we're using an external compiler (that already
|
||||||
|
// knows these headers).
|
||||||
|
cflags = append(cflags,
|
||||||
|
"-resource-dir="+resourceDir,
|
||||||
|
)
|
||||||
|
}
|
||||||
switch c.Target.Libc {
|
switch c.Target.Libc {
|
||||||
case "darwin-libSystem":
|
case "darwin-libSystem":
|
||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
cflags = append(cflags,
|
cflags = append(cflags,
|
||||||
"--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
|
"-nostdlibinc",
|
||||||
|
"-isystem", filepath.Join(root, "lib/macos-minimal-sdk/src/usr/include"),
|
||||||
)
|
)
|
||||||
case "picolibc":
|
case "picolibc":
|
||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
|
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
|
||||||
path, _ := c.LibcPath("picolibc")
|
path, _ := c.LibcPath("picolibc")
|
||||||
cflags = append(cflags,
|
cflags = append(cflags,
|
||||||
"--sysroot="+path,
|
"-nostdlibinc",
|
||||||
"-isystem", filepath.Join(path, "include"), // necessary for Xtensa
|
"-isystem", filepath.Join(path, "include"),
|
||||||
"-isystem", filepath.Join(picolibcDir, "include"),
|
"-isystem", filepath.Join(picolibcDir, "include"),
|
||||||
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
||||||
)
|
)
|
||||||
@@ -292,12 +311,17 @@ func (c *Config) CFlags() []string {
|
|||||||
)
|
)
|
||||||
case "wasi-libc":
|
case "wasi-libc":
|
||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
cflags = append(cflags, "--sysroot="+root+"/lib/wasi-libc/sysroot")
|
cflags = append(cflags,
|
||||||
|
"-nostdlibinc",
|
||||||
|
"-isystem", root+"/lib/wasi-libc/sysroot/include")
|
||||||
|
case "wasmbuiltins":
|
||||||
|
// nothing to add (library is purely for builtins)
|
||||||
case "mingw-w64":
|
case "mingw-w64":
|
||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
path, _ := c.LibcPath("mingw-w64")
|
path, _ := c.LibcPath("mingw-w64")
|
||||||
cflags = append(cflags,
|
cflags = append(cflags,
|
||||||
"--sysroot="+path,
|
"-nostdlibinc",
|
||||||
|
"-isystem", filepath.Join(path, "include"),
|
||||||
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
|
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
|
||||||
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
|
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
|
||||||
"-D_UCRT",
|
"-D_UCRT",
|
||||||
@@ -456,9 +480,6 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
|||||||
return nil, fmt.Errorf("unknown OpenOCD transport: %#v", c.Target.OpenOCDTransport)
|
return nil, fmt.Errorf("unknown OpenOCD transport: %#v", c.Target.OpenOCDTransport)
|
||||||
}
|
}
|
||||||
args = []string{"-f", "interface/" + openocdInterface + ".cfg"}
|
args = []string{"-f", "interface/" + openocdInterface + ".cfg"}
|
||||||
for _, cmd := range c.Target.OpenOCDCommands {
|
|
||||||
args = append(args, "-c", cmd)
|
|
||||||
}
|
|
||||||
if c.Target.OpenOCDTransport != "" {
|
if c.Target.OpenOCDTransport != "" {
|
||||||
transport := c.Target.OpenOCDTransport
|
transport := c.Target.OpenOCDTransport
|
||||||
if transport == "swd" {
|
if transport == "swd" {
|
||||||
@@ -470,6 +491,9 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
|||||||
args = append(args, "-c", "transport select "+transport)
|
args = append(args, "-c", "transport select "+transport)
|
||||||
}
|
}
|
||||||
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
|
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
|
||||||
|
for _, cmd := range c.Target.OpenOCDCommands {
|
||||||
|
args = append(args, "-c", cmd)
|
||||||
|
}
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
||||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||||
validSerialOptions = []string{"none", "uart", "usb"}
|
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
|
||||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||||
validPanicStrategyOptions = []string{"print", "trap"}
|
validPanicStrategyOptions = []string{"print", "trap"}
|
||||||
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
||||||
@@ -23,6 +23,7 @@ type Options struct {
|
|||||||
GOOS string // environment variable
|
GOOS string // environment variable
|
||||||
GOARCH string // environment variable
|
GOARCH string // environment variable
|
||||||
GOARM string // environment variable (only used with GOARCH=arm)
|
GOARM string // environment variable (only used with GOARCH=arm)
|
||||||
|
Directory string // working dir, leave it unset to use the current working dir
|
||||||
Target string
|
Target string
|
||||||
Opt string
|
Opt string
|
||||||
GC string
|
GC string
|
||||||
@@ -48,7 +49,6 @@ type Options struct {
|
|||||||
Programmer string
|
Programmer string
|
||||||
OpenOCDCommands []string
|
OpenOCDCommands []string
|
||||||
LLVMFeatures string
|
LLVMFeatures string
|
||||||
Directory string
|
|
||||||
PrintJSON bool
|
PrintJSON bool
|
||||||
Monitor bool
|
Monitor bool
|
||||||
BaudRate int
|
BaudRate int
|
||||||
|
|||||||
+61
-8
@@ -26,7 +26,7 @@ type TargetSpec struct {
|
|||||||
Inherits []string `json:"inherits,omitempty"`
|
Inherits []string `json:"inherits,omitempty"`
|
||||||
Triple string `json:"llvm-target,omitempty"`
|
Triple string `json:"llvm-target,omitempty"`
|
||||||
CPU string `json:"cpu,omitempty"`
|
CPU string `json:"cpu,omitempty"`
|
||||||
ABI string `json:"target-abi,omitempty"` // rougly equivalent to -mabi= flag
|
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
|
||||||
Features string `json:"features,omitempty"`
|
Features string `json:"features,omitempty"`
|
||||||
GOOS string `json:"goos,omitempty"`
|
GOOS string `json:"goos,omitempty"`
|
||||||
GOARCH string `json:"goarch,omitempty"`
|
GOARCH string `json:"goarch,omitempty"`
|
||||||
@@ -246,6 +246,43 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
return spec, nil
|
return spec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTargetSpecs retrieves target specifications from the TINYGOROOT targets
|
||||||
|
// directory. Only valid target JSON files are considered, and the function
|
||||||
|
// returns a map of target names to their respective TargetSpec.
|
||||||
|
func GetTargetSpecs() (map[string]*TargetSpec, error) {
|
||||||
|
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||||
|
entries, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not list targets: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
maps := map[string]*TargetSpec{}
|
||||||
|
for _, entry := range entries {
|
||||||
|
entryInfo, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get entry info: %w", err)
|
||||||
|
}
|
||||||
|
if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
|
||||||
|
// Only inspect JSON files.
|
||||||
|
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.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).
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := entry.Name()
|
||||||
|
name = name[:len(name)-5]
|
||||||
|
maps[name] = spec
|
||||||
|
}
|
||||||
|
return maps, nil
|
||||||
|
}
|
||||||
|
|
||||||
func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||||
// No target spec available. Use the default one, useful on most systems
|
// No target spec available. Use the default one, useful on most systems
|
||||||
// with a regular OS.
|
// with a regular OS.
|
||||||
@@ -264,10 +301,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
switch goarch {
|
switch goarch {
|
||||||
case "386":
|
case "386":
|
||||||
spec.CPU = "pentium4"
|
spec.CPU = "pentium4"
|
||||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||||
case "amd64":
|
case "amd64":
|
||||||
spec.CPU = "x86-64"
|
spec.CPU = "x86-64"
|
||||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||||
case "arm":
|
case "arm":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||||
@@ -282,9 +319,11 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
case "arm64":
|
case "arm64":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
if goos == "darwin" {
|
if goos == "darwin" {
|
||||||
spec.Features = "+neon"
|
spec.Features = "+fp-armv8,+neon"
|
||||||
} else { // windows, linux
|
} else if goos == "windows" {
|
||||||
spec.Features = "+neon,-fmv"
|
spec.Features = "+fp-armv8,+neon,-fmv"
|
||||||
|
} else { // linux
|
||||||
|
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
|
||||||
}
|
}
|
||||||
case "wasm":
|
case "wasm":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
@@ -312,6 +351,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.RTLib = "compiler-rt"
|
spec.RTLib = "compiler-rt"
|
||||||
spec.Libc = "musl"
|
spec.Libc = "musl"
|
||||||
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
||||||
|
if goarch == "arm64" {
|
||||||
|
// Disable outline atomics. For details, see:
|
||||||
|
// https://cpufun.substack.com/p/atomics-in-aarch64
|
||||||
|
// A better way would be to fully support outline atomics, which
|
||||||
|
// makes atomics slightly more efficient on systems with many cores.
|
||||||
|
// But the instructions are only supported on newer aarch64 CPUs, so
|
||||||
|
// this feature is normally put in a system library which does
|
||||||
|
// feature detection for you.
|
||||||
|
// We take the lazy way out and simply disable this feature, instead
|
||||||
|
// of enabling it in compiler-rt (which is a bit more complicated).
|
||||||
|
// We don't really need this feature anyway as we don't even support
|
||||||
|
// proper threading.
|
||||||
|
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
|
||||||
|
}
|
||||||
} else if goos == "windows" {
|
} else if goos == "windows" {
|
||||||
spec.Linker = "ld.lld"
|
spec.Linker = "ld.lld"
|
||||||
spec.Libc = "mingw-w64"
|
spec.Libc = "mingw-w64"
|
||||||
@@ -344,12 +397,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.Linker = "wasm-ld"
|
spec.Linker = "wasm-ld"
|
||||||
spec.RTLib = "compiler-rt"
|
spec.RTLib = "compiler-rt"
|
||||||
spec.Libc = "wasi-libc"
|
spec.Libc = "wasi-libc"
|
||||||
spec.DefaultStackSize = 1024 * 32 // 32kB
|
spec.DefaultStackSize = 1024 * 64 // 64kB
|
||||||
spec.LDFlags = append(spec.LDFlags,
|
spec.LDFlags = append(spec.LDFlags,
|
||||||
"--stack-first",
|
"--stack-first",
|
||||||
"--no-demangle",
|
"--no-demangle",
|
||||||
)
|
)
|
||||||
spec.Emulator = "wasmtime --mapdir=/tmp::{tmpDir} {}"
|
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||||
"src/runtime/asm_tinygowasm.S",
|
"src/runtime/asm_tinygowasm.S",
|
||||||
"src/internal/task/task_asyncify_wasm.S",
|
"src/internal/task/task_asyncify_wasm.S",
|
||||||
|
|||||||
+6
-2
@@ -16,14 +16,18 @@ import "tinygo.org/x/go-llvm"
|
|||||||
|
|
||||||
var stdlibAliases = map[string]string{
|
var stdlibAliases = map[string]string{
|
||||||
// crypto packages
|
// crypto packages
|
||||||
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
|
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
|
||||||
"crypto/ed25519/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
|
"crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
|
||||||
"crypto/md5.block": "crypto/md5.blockGeneric",
|
"crypto/md5.block": "crypto/md5.blockGeneric",
|
||||||
"crypto/sha1.block": "crypto/sha1.blockGeneric",
|
"crypto/sha1.block": "crypto/sha1.blockGeneric",
|
||||||
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
|
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
|
||||||
"crypto/sha256.block": "crypto/sha256.blockGeneric",
|
"crypto/sha256.block": "crypto/sha256.blockGeneric",
|
||||||
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
||||||
|
|
||||||
|
// AES
|
||||||
|
"crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock",
|
||||||
|
"crypto/aes.encryptBlockAsm": "crypto/aes.encryptBlock",
|
||||||
|
|
||||||
// math package
|
// math package
|
||||||
"math.archHypot": "math.hypot",
|
"math.archHypot": "math.hypot",
|
||||||
"math.archMax": "math.max",
|
"math.archMax": "math.max",
|
||||||
|
|||||||
+2
-2
@@ -135,7 +135,7 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
|
|||||||
|
|
||||||
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in an
|
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in an
|
||||||
// uintptr if uintptrs were signed.
|
// uintptr if uintptrs were signed.
|
||||||
maxBufSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false))
|
maxBufSize := b.CreateLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||||
if elementSize > maxBufSize.ZExtValue() {
|
if elementSize > maxBufSize.ZExtValue() {
|
||||||
b.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize))
|
b.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize))
|
||||||
return
|
return
|
||||||
@@ -150,7 +150,7 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
|
|||||||
|
|
||||||
// Make sure maxBufSize has the same type as bufSize.
|
// Make sure maxBufSize has the same type as bufSize.
|
||||||
if maxBufSize.Type() != bufSize.Type() {
|
if maxBufSize.Type() != bufSize.Type() {
|
||||||
maxBufSize = llvm.ConstZExt(maxBufSize, bufSize.Type())
|
maxBufSize = b.CreateZExt(maxBufSize, bufSize.Type(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the check for a too large (or negative) buffer size.
|
// Do the check for a too large (or negative) buffer size.
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,37 +12,13 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
|||||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||||
if strings.HasPrefix(b.Triple, "avr") {
|
|
||||||
// AtomicRMW does not work on AVR as intended:
|
|
||||||
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
|
|
||||||
// - The result is the new value instead of the old value
|
|
||||||
vType := val.Type()
|
|
||||||
name := fmt.Sprintf("__sync_fetch_and_add_%d", vType.IntTypeWidth()/8)
|
|
||||||
fn := b.mod.NamedFunction(name)
|
|
||||||
if fn.IsNil() {
|
|
||||||
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType}, false))
|
|
||||||
}
|
|
||||||
oldVal := b.createCall(fn.GlobalValueType(), fn, []llvm.Value{ptr, val}, "")
|
|
||||||
// Return the new value, not the original value returned.
|
|
||||||
return b.CreateAdd(oldVal, val, "")
|
|
||||||
}
|
|
||||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||||
// Return the new value, not the original value returned by atomicrmw.
|
// Return the new value, not the original value returned by atomicrmw.
|
||||||
return b.CreateAdd(oldVal, val, "")
|
return b.CreateAdd(oldVal, val, "")
|
||||||
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
||||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||||
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
|
|
||||||
if isPointer {
|
|
||||||
// atomicrmw only supports integers, so cast to an integer.
|
|
||||||
// TODO: this is fixed in LLVM 15.
|
|
||||||
val = b.CreatePtrToInt(val, b.uintptrType, "")
|
|
||||||
ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "")
|
|
||||||
}
|
|
||||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||||
if isPointer {
|
|
||||||
oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "")
|
|
||||||
}
|
|
||||||
return oldVal
|
return oldVal
|
||||||
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
||||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
@@ -63,24 +36,6 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
|||||||
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
||||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||||
if strings.HasPrefix(b.Triple, "avr") {
|
|
||||||
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
|
|
||||||
vType := val.Type()
|
|
||||||
isPointer := vType.TypeKind() == llvm.PointerTypeKind
|
|
||||||
if isPointer {
|
|
||||||
// libcalls only supports integers, so cast to an integer.
|
|
||||||
vType = b.uintptrType
|
|
||||||
val = b.CreatePtrToInt(val, vType, "")
|
|
||||||
ptr = b.CreateBitCast(ptr, llvm.PointerType(vType, 0), "")
|
|
||||||
}
|
|
||||||
name := fmt.Sprintf("__atomic_store_%d", vType.IntTypeWidth()/8)
|
|
||||||
fn := b.mod.NamedFunction(name)
|
|
||||||
if fn.IsNil() {
|
|
||||||
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
|
|
||||||
}
|
|
||||||
b.createCall(fn.GlobalValueType(), fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, "")
|
|
||||||
return llvm.Value{}
|
|
||||||
}
|
|
||||||
store := b.CreateStore(val, ptr)
|
store := b.CreateStore(val, ptr)
|
||||||
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||||
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name
|
|||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
panic("trying to call non-existent function: " + fn.RelString(nil))
|
panic("trying to call non-existent function: " + fn.RelString(nil))
|
||||||
}
|
}
|
||||||
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
|
args = append(args, llvm.Undef(b.dataPtrType)) // unused context parameter
|
||||||
if isInvoke {
|
if isInvoke {
|
||||||
return b.createInvoke(fnType, llvmFn, args, name)
|
return b.createInvoke(fnType, llvmFn, args, name)
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-26
@@ -33,28 +33,27 @@ func (b *builder) createChanSend(instr *ssa.Send) {
|
|||||||
// store value-to-send
|
// store value-to-send
|
||||||
valueType := b.getLLVMType(instr.X.Type())
|
valueType := b.getLLVMType(instr.X.Type())
|
||||||
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
|
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
|
||||||
var valueAlloca, valueAllocaCast, valueAllocaSize llvm.Value
|
var valueAlloca, valueAllocaSize llvm.Value
|
||||||
if isZeroSize {
|
if isZeroSize {
|
||||||
valueAlloca = llvm.ConstNull(llvm.PointerType(valueType, 0))
|
valueAlloca = llvm.ConstNull(b.dataPtrType)
|
||||||
valueAllocaCast = llvm.ConstNull(b.i8ptrType)
|
|
||||||
} else {
|
} else {
|
||||||
valueAlloca, valueAllocaCast, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
|
valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
|
||||||
b.CreateStore(chanValue, valueAlloca)
|
b.CreateStore(chanValue, valueAlloca)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate blockedlist buffer.
|
// Allocate blockedlist buffer.
|
||||||
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
|
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
|
||||||
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
||||||
|
|
||||||
// Do the send.
|
// Do the send.
|
||||||
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
|
||||||
|
|
||||||
// End the lifetime of the allocas.
|
// End the lifetime of the allocas.
|
||||||
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
||||||
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
||||||
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
|
||||||
if !isZeroSize {
|
if !isZeroSize {
|
||||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,28 +65,27 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
|||||||
|
|
||||||
// Allocate memory to receive into.
|
// Allocate memory to receive into.
|
||||||
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
|
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
|
||||||
var valueAlloca, valueAllocaCast, valueAllocaSize llvm.Value
|
var valueAlloca, valueAllocaSize llvm.Value
|
||||||
if isZeroSize {
|
if isZeroSize {
|
||||||
valueAlloca = llvm.ConstNull(llvm.PointerType(valueType, 0))
|
valueAlloca = llvm.ConstNull(b.dataPtrType)
|
||||||
valueAllocaCast = llvm.ConstNull(b.i8ptrType)
|
|
||||||
} else {
|
} else {
|
||||||
valueAlloca, valueAllocaCast, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
|
valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate blockedlist buffer.
|
// Allocate blockedlist buffer.
|
||||||
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
|
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
|
||||||
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
||||||
|
|
||||||
// Do the receive.
|
// Do the receive.
|
||||||
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
|
||||||
var received llvm.Value
|
var received llvm.Value
|
||||||
if isZeroSize {
|
if isZeroSize {
|
||||||
received = llvm.ConstNull(valueType)
|
received = llvm.ConstNull(valueType)
|
||||||
} else {
|
} else {
|
||||||
received = b.CreateLoad(valueType, valueAlloca, "chan.received")
|
received = b.CreateLoad(valueType, valueAlloca, "chan.received")
|
||||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
|
||||||
}
|
}
|
||||||
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
|
||||||
|
|
||||||
if unop.CommaOk {
|
if unop.CommaOk {
|
||||||
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{valueType, b.ctx.Int1Type()}, false))
|
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{valueType, b.ctx.Int1Type()}, false))
|
||||||
@@ -159,8 +157,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
sendValue := b.getValue(state.Send, state.Pos)
|
sendValue := b.getValue(state.Send, state.Pos)
|
||||||
alloca := llvmutil.CreateEntryBlockAlloca(b.Builder, sendValue.Type(), "select.send.value")
|
alloca := llvmutil.CreateEntryBlockAlloca(b.Builder, sendValue.Type(), "select.send.value")
|
||||||
b.CreateStore(sendValue, alloca)
|
b.CreateStore(sendValue, alloca)
|
||||||
ptr := b.CreateBitCast(alloca, b.i8ptrType, "")
|
selectState = b.CreateInsertValue(selectState, alloca, 1, "")
|
||||||
selectState = b.CreateInsertValue(selectState, ptr, 1, "")
|
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
@@ -168,10 +165,10 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a receive buffer, where the received value will be stored.
|
// Create a receive buffer, where the received value will be stored.
|
||||||
recvbuf := llvm.Undef(b.i8ptrType)
|
recvbuf := llvm.Undef(b.dataPtrType)
|
||||||
if recvbufSize != 0 {
|
if recvbufSize != 0 {
|
||||||
allocaType := llvm.ArrayType(b.ctx.Int8Type(), int(recvbufSize))
|
allocaType := llvm.ArrayType(b.ctx.Int8Type(), int(recvbufSize))
|
||||||
recvbufAlloca, _, _ := b.createTemporaryAlloca(allocaType, "select.recvbuf.alloca")
|
recvbufAlloca, _ := b.createTemporaryAlloca(allocaType, "select.recvbuf.alloca")
|
||||||
recvbufAlloca.SetAlignment(recvbufAlign)
|
recvbufAlloca.SetAlignment(recvbufAlign)
|
||||||
recvbuf = b.CreateGEP(allocaType, recvbufAlloca, []llvm.Value{
|
recvbuf = b.CreateGEP(allocaType, recvbufAlloca, []llvm.Value{
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
@@ -181,7 +178,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
|
|
||||||
// Create the states slice (allocated on the stack).
|
// Create the states slice (allocated on the stack).
|
||||||
statesAllocaType := llvm.ArrayType(chanSelectStateType, len(selectStates))
|
statesAllocaType := llvm.ArrayType(chanSelectStateType, len(selectStates))
|
||||||
statesAlloca, statesI8, statesSize := b.createTemporaryAlloca(statesAllocaType, "select.states.alloca")
|
statesAlloca, statesSize := b.createTemporaryAlloca(statesAllocaType, "select.states.alloca")
|
||||||
for i, state := range selectStates {
|
for i, state := range selectStates {
|
||||||
// Set each slice element to the appropriate channel.
|
// Set each slice element to the appropriate channel.
|
||||||
gep := b.CreateGEP(statesAllocaType, statesAlloca, []llvm.Value{
|
gep := b.CreateGEP(statesAllocaType, statesAlloca, []llvm.Value{
|
||||||
@@ -202,7 +199,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
// Stack-allocate operation structures.
|
// Stack-allocate operation structures.
|
||||||
// If these were simply created as a slice, they would heap-allocate.
|
// If these were simply created as a slice, they would heap-allocate.
|
||||||
chBlockAllocaType := llvm.ArrayType(b.getLLVMRuntimeType("channelBlockedList"), len(selectStates))
|
chBlockAllocaType := llvm.ArrayType(b.getLLVMRuntimeType("channelBlockedList"), len(selectStates))
|
||||||
chBlockAlloca, chBlockAllocaPtr, chBlockSize := b.createTemporaryAlloca(chBlockAllocaType, "select.block.alloca")
|
chBlockAlloca, chBlockSize := b.createTemporaryAlloca(chBlockAllocaType, "select.block.alloca")
|
||||||
chBlockLen := llvm.ConstInt(b.uintptrType, uint64(len(selectStates)), false)
|
chBlockLen := llvm.ConstInt(b.uintptrType, uint64(len(selectStates)), false)
|
||||||
chBlockPtr := b.CreateGEP(chBlockAllocaType, chBlockAlloca, []llvm.Value{
|
chBlockPtr := b.CreateGEP(chBlockAllocaType, chBlockAlloca, []llvm.Value{
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
@@ -216,7 +213,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
}, "select.result")
|
}, "select.result")
|
||||||
|
|
||||||
// Terminate the lifetime of the operation structures.
|
// Terminate the lifetime of the operation structures.
|
||||||
b.emitLifetimeEnd(chBlockAllocaPtr, chBlockSize)
|
b.emitLifetimeEnd(chBlockAlloca, chBlockSize)
|
||||||
} else {
|
} else {
|
||||||
results = b.createRuntimeCall("tryChanSelect", []llvm.Value{
|
results = b.createRuntimeCall("tryChanSelect", []llvm.Value{
|
||||||
recvbuf,
|
recvbuf,
|
||||||
@@ -225,7 +222,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Terminate the lifetime of the states alloca.
|
// Terminate the lifetime of the states alloca.
|
||||||
b.emitLifetimeEnd(statesI8, statesSize)
|
b.emitLifetimeEnd(statesAlloca, statesSize)
|
||||||
|
|
||||||
// The result value does not include all the possible received values,
|
// The result value does not include all the possible received values,
|
||||||
// because we can't load them in advance. Instead, the *ssa.Extract
|
// because we can't load them in advance. Instead, the *ssa.Extract
|
||||||
@@ -265,7 +262,6 @@ func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
|
|||||||
// it to the correct type, and dereference it.
|
// it to the correct type, and dereference it.
|
||||||
recvbuf := b.selectRecvBuf[expr.Tuple.(*ssa.Select)]
|
recvbuf := b.selectRecvBuf[expr.Tuple.(*ssa.Select)]
|
||||||
typ := b.getLLVMType(expr.Type())
|
typ := b.getLLVMType(expr.Type())
|
||||||
ptr := b.CreateBitCast(recvbuf, llvm.PointerType(typ, 0), "")
|
return b.CreateLoad(typ, recvbuf, "")
|
||||||
return b.CreateLoad(typ, ptr, "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-62
@@ -53,8 +53,10 @@ type Config struct {
|
|||||||
Scheduler string
|
Scheduler string
|
||||||
AutomaticStackSize bool
|
AutomaticStackSize bool
|
||||||
DefaultStackSize uint64
|
DefaultStackSize uint64
|
||||||
|
MaxStackAlloc uint64
|
||||||
NeedsStackObjects bool
|
NeedsStackObjects bool
|
||||||
Debug bool // Whether to emit debug information in the LLVM module.
|
Debug bool // Whether to emit debug information in the LLVM module.
|
||||||
|
PanicStrategy string
|
||||||
}
|
}
|
||||||
|
|
||||||
// compilerContext contains function-independent data that should still be
|
// compilerContext contains function-independent data that should still be
|
||||||
@@ -75,10 +77,9 @@ type compilerContext struct {
|
|||||||
machine llvm.TargetMachine
|
machine llvm.TargetMachine
|
||||||
targetData llvm.TargetData
|
targetData llvm.TargetData
|
||||||
intType llvm.Type
|
intType llvm.Type
|
||||||
i8ptrType llvm.Type // for convenience
|
dataPtrType llvm.Type // pointer in address space 0
|
||||||
rawVoidFuncType llvm.Type // for convenience
|
funcPtrType llvm.Type // pointer in function address space (1 for AVR, 0 elsewhere)
|
||||||
funcPtrAddrSpace int
|
funcPtrAddrSpace int
|
||||||
hasTypedPointers bool // for LLVM 14 backwards compatibility
|
|
||||||
uintptrType llvm.Type
|
uintptrType llvm.Type
|
||||||
program *ssa.Program
|
program *ssa.Program
|
||||||
diagnostics []error
|
diagnostics []error
|
||||||
@@ -123,13 +124,12 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
|
|||||||
} else {
|
} else {
|
||||||
panic("unknown pointer size")
|
panic("unknown pointer size")
|
||||||
}
|
}
|
||||||
c.i8ptrType = llvm.PointerType(c.ctx.Int8Type(), 0)
|
c.dataPtrType = llvm.PointerType(c.ctx.Int8Type(), 0)
|
||||||
|
|
||||||
dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false)
|
dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false)
|
||||||
dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType)
|
dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType)
|
||||||
c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace()
|
c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace()
|
||||||
c.hasTypedPointers = c.i8ptrType != llvm.PointerType(c.ctx.Int16Type(), 0) // with opaque pointers, all pointers are the same type (LLVM 15+)
|
c.funcPtrType = dummyFunc.Type()
|
||||||
c.rawVoidFuncType = dummyFunc.Type()
|
|
||||||
dummyFunc.EraseFromParentAsFunction()
|
dummyFunc.EraseFromParentAsFunction()
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@@ -417,16 +417,14 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
|||||||
case types.Uintptr:
|
case types.Uintptr:
|
||||||
return c.uintptrType
|
return c.uintptrType
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
return c.i8ptrType
|
return c.dataPtrType
|
||||||
default:
|
default:
|
||||||
panic("unknown basic type: " + typ.String())
|
panic("unknown basic type: " + typ.String())
|
||||||
}
|
}
|
||||||
case *types.Chan:
|
case *types.Chan, *types.Map, *types.Pointer:
|
||||||
return llvm.PointerType(c.getLLVMRuntimeType("channel"), 0)
|
return c.dataPtrType // all pointers are the same
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
return c.getLLVMRuntimeType("_interface")
|
return c.getLLVMRuntimeType("_interface")
|
||||||
case *types.Map:
|
|
||||||
return llvm.PointerType(c.getLLVMRuntimeType("hashmap"), 0)
|
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
if st, ok := typ.Underlying().(*types.Struct); ok {
|
if st, ok := typ.Underlying().(*types.Struct); ok {
|
||||||
// Structs are a special case. While other named types are ignored
|
// Structs are a special case. While other named types are ignored
|
||||||
@@ -441,21 +439,11 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
|||||||
return llvmType
|
return llvmType
|
||||||
}
|
}
|
||||||
return c.getLLVMType(typ.Underlying())
|
return c.getLLVMType(typ.Underlying())
|
||||||
case *types.Pointer:
|
|
||||||
if c.hasTypedPointers {
|
|
||||||
ptrTo := c.getLLVMType(typ.Elem())
|
|
||||||
return llvm.PointerType(ptrTo, 0)
|
|
||||||
}
|
|
||||||
return c.i8ptrType // all pointers are the same
|
|
||||||
case *types.Signature: // function value
|
case *types.Signature: // function value
|
||||||
return c.getFuncType(typ)
|
return c.getFuncType(typ)
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
ptrType := c.i8ptrType
|
|
||||||
if c.hasTypedPointers {
|
|
||||||
ptrType = llvm.PointerType(c.getLLVMType(typ.Elem()), 0)
|
|
||||||
}
|
|
||||||
members := []llvm.Type{
|
members := []llvm.Type{
|
||||||
ptrType,
|
c.dataPtrType,
|
||||||
c.uintptrType, // len
|
c.uintptrType, // len
|
||||||
c.uintptrType, // cap
|
c.uintptrType, // cap
|
||||||
}
|
}
|
||||||
@@ -545,8 +533,8 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
|||||||
Elements: []llvm.Metadata{
|
Elements: []llvm.Metadata{
|
||||||
c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
|
c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
|
||||||
Name: "ptr",
|
Name: "ptr",
|
||||||
SizeInBits: c.targetData.TypeAllocSize(c.i8ptrType) * 8,
|
SizeInBits: c.targetData.TypeAllocSize(c.dataPtrType) * 8,
|
||||||
AlignInBits: uint32(c.targetData.ABITypeAlignment(c.i8ptrType)) * 8,
|
AlignInBits: uint32(c.targetData.ABITypeAlignment(c.dataPtrType)) * 8,
|
||||||
OffsetInBits: 0,
|
OffsetInBits: 0,
|
||||||
Type: c.getDIType(types.NewPointer(types.Typ[types.Byte])),
|
Type: c.getDIType(types.NewPointer(types.Typ[types.Byte])),
|
||||||
}),
|
}),
|
||||||
@@ -1548,21 +1536,18 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
src := argValues[0]
|
src := argValues[0]
|
||||||
elems := argValues[1]
|
elems := argValues[1]
|
||||||
srcBuf := b.CreateExtractValue(src, 0, "append.srcBuf")
|
srcBuf := b.CreateExtractValue(src, 0, "append.srcBuf")
|
||||||
srcPtr := b.CreateBitCast(srcBuf, b.i8ptrType, "append.srcPtr")
|
|
||||||
srcLen := b.CreateExtractValue(src, 1, "append.srcLen")
|
srcLen := b.CreateExtractValue(src, 1, "append.srcLen")
|
||||||
srcCap := b.CreateExtractValue(src, 2, "append.srcCap")
|
srcCap := b.CreateExtractValue(src, 2, "append.srcCap")
|
||||||
elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf")
|
elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf")
|
||||||
elemsPtr := b.CreateBitCast(elemsBuf, b.i8ptrType, "append.srcPtr")
|
|
||||||
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
|
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
|
||||||
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
||||||
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
||||||
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcPtr, elemsPtr, srcLen, srcCap, elemsLen, elemSize}, "append.new")
|
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
|
||||||
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
|
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
|
||||||
newBuf := b.CreateBitCast(newPtr, srcBuf.Type(), "append.newBuf")
|
|
||||||
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
newLen := b.CreateExtractValue(result, 1, "append.newLen")
|
||||||
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
newCap := b.CreateExtractValue(result, 2, "append.newCap")
|
||||||
newSlice := llvm.Undef(src.Type())
|
newSlice := llvm.Undef(src.Type())
|
||||||
newSlice = b.CreateInsertValue(newSlice, newBuf, 0, "")
|
newSlice = b.CreateInsertValue(newSlice, newPtr, 0, "")
|
||||||
newSlice = b.CreateInsertValue(newSlice, newLen, 1, "")
|
newSlice = b.CreateInsertValue(newSlice, newLen, 1, "")
|
||||||
newSlice = b.CreateInsertValue(newSlice, newCap, 2, "")
|
newSlice = b.CreateInsertValue(newSlice, newCap, 2, "")
|
||||||
return newSlice, nil
|
return newSlice, nil
|
||||||
@@ -1610,9 +1595,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
|
|
||||||
// The pointer to the data to be cleared.
|
// The pointer to the data to be cleared.
|
||||||
llvmBuf := b.CreateExtractValue(value, 0, "buf")
|
llvmBuf := b.CreateExtractValue(value, 0, "buf")
|
||||||
if llvmBuf.Type() != b.i8ptrType { // compatibility with LLVM 14
|
|
||||||
llvmBuf = b.CreateBitCast(llvmBuf, b.i8ptrType, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The length (in bytes) to be cleared.
|
// The length (in bytes) to be cleared.
|
||||||
llvmLen := b.CreateExtractValue(value, 1, "len")
|
llvmLen := b.CreateExtractValue(value, 1, "len")
|
||||||
@@ -1647,8 +1629,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
|
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
|
||||||
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
|
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
|
||||||
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
|
||||||
dstBuf = b.CreateBitCast(dstBuf, b.i8ptrType, "copy.dstPtr")
|
|
||||||
srcBuf = b.CreateBitCast(srcBuf, b.i8ptrType, "copy.srcPtr")
|
|
||||||
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
|
||||||
return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
|
return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
|
||||||
case "delete":
|
case "delete":
|
||||||
@@ -1876,6 +1856,13 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
supportsRecover = 1
|
supportsRecover = 1
|
||||||
}
|
}
|
||||||
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
|
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
|
||||||
|
case name == "runtime.panicStrategy":
|
||||||
|
// These constants are defined in src/runtime/panic.go.
|
||||||
|
panicStrategy := map[string]uint64{
|
||||||
|
"print": 1, // panicStrategyPrint
|
||||||
|
"trap": 2, // panicStrategyTrap
|
||||||
|
}[b.Config.PanicStrategy]
|
||||||
|
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
|
||||||
case name == "runtime/interrupt.New":
|
case name == "runtime/interrupt.New":
|
||||||
return b.createInterruptGlobal(instr)
|
return b.createInterruptGlobal(instr)
|
||||||
}
|
}
|
||||||
@@ -1888,14 +1875,13 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
switch value := instr.Value.(type) {
|
switch value := instr.Value.(type) {
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
// Regular function call. No context is necessary.
|
// Regular function call. No context is necessary.
|
||||||
context = llvm.Undef(b.i8ptrType)
|
context = llvm.Undef(b.dataPtrType)
|
||||||
if info.variadic && len(fn.Params) == 0 {
|
if info.variadic && len(fn.Params) == 0 {
|
||||||
// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
|
// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
|
||||||
// Eventually we might be able to eliminate this special case
|
// Eventually we might be able to eliminate this special case
|
||||||
// entirely. For details, see:
|
// entirely. For details, see:
|
||||||
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
|
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
|
||||||
calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false)
|
calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false)
|
||||||
callee = llvm.ConstBitCast(callee, llvm.PointerType(calleeType, b.funcPtrAddrSpace))
|
|
||||||
}
|
}
|
||||||
case *ssa.MakeClosure:
|
case *ssa.MakeClosure:
|
||||||
// A call on a func value, but the callee is trivial to find. For
|
// A call on a func value, but the callee is trivial to find. For
|
||||||
@@ -1923,13 +1909,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
params = append(params, typecode)
|
params = append(params, typecode)
|
||||||
callee = b.getInvokeFunction(instr)
|
callee = b.getInvokeFunction(instr)
|
||||||
calleeType = callee.GlobalValueType()
|
calleeType = callee.GlobalValueType()
|
||||||
context = llvm.Undef(b.i8ptrType)
|
context = llvm.Undef(b.dataPtrType)
|
||||||
} else {
|
} else {
|
||||||
// Function pointer.
|
// Function pointer.
|
||||||
value := b.getValue(instr.Value, getPos(instr))
|
value := b.getValue(instr.Value, getPos(instr))
|
||||||
// This is a func value, which cannot be called directly. We have to
|
// This is a func value, which cannot be called directly. We have to
|
||||||
// extract the function pointer and context first from the func value.
|
// extract the function pointer and context first from the func value.
|
||||||
calleeType, callee, context = b.decodeFuncValue(value, instr.Value.Type().Underlying().(*types.Signature))
|
callee, context = b.decodeFuncValue(value)
|
||||||
|
calleeType = b.getLLVMFunctionType(instr.Value.Type().Underlying().(*types.Signature))
|
||||||
b.createNilCheck(instr.Value, callee, "fpcall")
|
b.createNilCheck(instr.Value, callee, "fpcall")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1962,7 +1949,7 @@ func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
|
|||||||
return llvm.Undef(b.getLLVMType(expr.Type()))
|
return llvm.Undef(b.getLLVMType(expr.Type()))
|
||||||
}
|
}
|
||||||
_, fn := b.getFunction(expr)
|
_, fn := b.getFunction(expr)
|
||||||
return b.createFuncValue(fn, llvm.Undef(b.i8ptrType), expr.Signature)
|
return b.createFuncValue(fn, llvm.Undef(b.dataPtrType), expr.Signature)
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
value := b.getGlobal(expr)
|
value := b.getGlobal(expr)
|
||||||
if value.IsNil() {
|
if value.IsNil() {
|
||||||
@@ -2019,8 +2006,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||||
size := b.targetData.TypeAllocSize(typ)
|
size := b.targetData.TypeAllocSize(typ)
|
||||||
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
|
// Move all "large" allocations to the heap.
|
||||||
if expr.Heap || size > 256 {
|
if expr.Heap || size > b.MaxStackAlloc {
|
||||||
// Calculate ^uintptr(0)
|
// Calculate ^uintptr(0)
|
||||||
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
||||||
if size > maxSize {
|
if size > maxSize {
|
||||||
@@ -2030,7 +2017,6 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
layoutValue := b.createObjectLayout(typ, expr.Pos())
|
layoutValue := b.createObjectLayout(typ, expr.Pos())
|
||||||
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
|
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
|
||||||
buf = b.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
} else {
|
} else {
|
||||||
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
|
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
|
||||||
@@ -2076,10 +2062,6 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
value = b.CreateInsertValue(value, field, i, "changetype.struct")
|
value = b.CreateInsertValue(value, field, i, "changetype.struct")
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
case llvm.PointerTypeKind:
|
|
||||||
// This can happen with pointers to structs. This case is easy:
|
|
||||||
// simply bitcast the pointer to the destination type.
|
|
||||||
return b.CreateBitCast(x, llvmType, "changetype.pointer"), nil
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
|
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
|
||||||
}
|
}
|
||||||
@@ -2156,12 +2138,12 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
// Can't load directly from array (as index is non-constant), so
|
// Can't load directly from array (as index is non-constant), so
|
||||||
// have to do it using an alloca+gep+load.
|
// have to do it using an alloca+gep+load.
|
||||||
arrayType := collection.Type()
|
arrayType := collection.Type()
|
||||||
alloca, allocaPtr, allocaSize := b.createTemporaryAlloca(arrayType, "index.alloca")
|
alloca, allocaSize := b.createTemporaryAlloca(arrayType, "index.alloca")
|
||||||
b.CreateStore(collection, alloca)
|
b.CreateStore(collection, alloca)
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
ptr := b.CreateInBoundsGEP(arrayType, alloca, []llvm.Value{zero, index}, "index.gep")
|
ptr := b.CreateInBoundsGEP(arrayType, alloca, []llvm.Value{zero, index}, "index.gep")
|
||||||
result := b.CreateLoad(arrayType.ElementType(), ptr, "index.load")
|
result := b.CreateLoad(arrayType.ElementType(), ptr, "index.load")
|
||||||
b.emitLifetimeEnd(allocaPtr, allocaSize)
|
b.emitLifetimeEnd(alloca, allocaSize)
|
||||||
return result, nil
|
return result, nil
|
||||||
default:
|
default:
|
||||||
panic("unknown *ssa.Index type")
|
panic("unknown *ssa.Index type")
|
||||||
@@ -2199,7 +2181,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure index is at least the size of uintptr becuase getelementptr
|
// Make sure index is at least the size of uintptr because getelementptr
|
||||||
// assumes index is a signed integer.
|
// assumes index is a signed integer.
|
||||||
index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
|
index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
|
||||||
|
|
||||||
@@ -2264,7 +2246,6 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
||||||
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
|
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
|
||||||
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
|
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
|
||||||
slicePtr = b.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
|
|
||||||
|
|
||||||
// Extend or truncate if necessary. This is safe as we've already done
|
// Extend or truncate if necessary. This is safe as we've already done
|
||||||
// the bounds check.
|
// the bounds check.
|
||||||
@@ -2310,7 +2291,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
default:
|
default:
|
||||||
panic("unknown type in range: " + typ.String())
|
panic("unknown type in range: " + typ.String())
|
||||||
}
|
}
|
||||||
it, _, _ := b.createTemporaryAlloca(iteratorType, "range.it")
|
it, _ := b.createTemporaryAlloca(iteratorType, "range.it")
|
||||||
b.CreateStore(llvm.ConstNull(iteratorType), it)
|
b.CreateStore(llvm.ConstNull(iteratorType), it)
|
||||||
return it, nil
|
return it, nil
|
||||||
case *ssa.Select:
|
case *ssa.Select:
|
||||||
@@ -2478,7 +2459,6 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()
|
arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()
|
||||||
b.createSliceToArrayPointerCheck(sliceLen, arrayLen)
|
b.createSliceToArrayPointerCheck(sliceLen, arrayLen)
|
||||||
ptr := b.CreateExtractValue(slice, 0, "")
|
ptr := b.CreateExtractValue(slice, 0, "")
|
||||||
ptr = b.CreateBitCast(ptr, b.getLLVMType(expr.Type()), "")
|
|
||||||
return ptr, nil
|
return ptr, nil
|
||||||
case *ssa.TypeAssert:
|
case *ssa.TypeAssert:
|
||||||
return b.createTypeAssert(expr), nil
|
return b.createTypeAssert(expr), nil
|
||||||
@@ -2577,7 +2557,7 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
|
|||||||
sizeY := b.targetData.TypeAllocSize(y.Type())
|
sizeY := b.targetData.TypeAllocSize(y.Type())
|
||||||
|
|
||||||
// Check if the shift is bigger than the bit-width of the shifted value.
|
// Check if the shift is bigger than the bit-width of the shifted value.
|
||||||
// This is UB in LLVM, so it needs to be handled seperately.
|
// This is UB in LLVM, so it needs to be handled separately.
|
||||||
// The Go spec indirectly defines the result as 0.
|
// The Go spec indirectly defines the result as 0.
|
||||||
// Negative shifts are handled earlier, so we can treat y as unsigned.
|
// Negative shifts are handled earlier, so we can treat y as unsigned.
|
||||||
overshifted := b.CreateICmp(llvm.IntUGE, y, llvm.ConstInt(y.Type(), 8*sizeX, false), "shift.overflow")
|
overshifted := b.CreateICmp(llvm.IntUGE, y, llvm.ConstInt(y.Type(), 8*sizeX, false), "shift.overflow")
|
||||||
@@ -2944,16 +2924,16 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
|
|||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
||||||
strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero})
|
strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero})
|
||||||
} else {
|
} else {
|
||||||
strPtr = llvm.ConstNull(c.i8ptrType)
|
strPtr = llvm.ConstNull(c.dataPtrType)
|
||||||
}
|
}
|
||||||
strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen})
|
strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen})
|
||||||
return strObj
|
return strObj
|
||||||
} else if typ.Kind() == types.UnsafePointer {
|
} else if typ.Kind() == types.UnsafePointer {
|
||||||
if !expr.IsNil() {
|
if !expr.IsNil() {
|
||||||
value, _ := constant.Uint64Val(constant.ToInt(expr.Value))
|
value, _ := constant.Uint64Val(constant.ToInt(expr.Value))
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.i8ptrType)
|
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.dataPtrType)
|
||||||
}
|
}
|
||||||
return llvm.ConstNull(c.i8ptrType)
|
return llvm.ConstNull(c.dataPtrType)
|
||||||
} else if typ.Info()&types.IsUnsigned != 0 {
|
} else if typ.Info()&types.IsUnsigned != 0 {
|
||||||
n, _ := constant.Uint64Val(constant.ToInt(expr.Value))
|
n, _ := constant.Uint64Val(constant.ToInt(expr.Value))
|
||||||
return llvm.ConstInt(llvmType, n, false)
|
return llvm.ConstInt(llvmType, n, false)
|
||||||
@@ -2997,7 +2977,7 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
|
|||||||
// Create a generic nil interface with no dynamic type (typecode=0).
|
// Create a generic nil interface with no dynamic type (typecode=0).
|
||||||
fields := []llvm.Value{
|
fields := []llvm.Value{
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
llvm.ConstInt(c.uintptrType, 0, false),
|
||||||
llvm.ConstPointerNull(c.i8ptrType),
|
llvm.ConstPointerNull(c.dataPtrType),
|
||||||
}
|
}
|
||||||
return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields)
|
return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields)
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
@@ -3014,8 +2994,7 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
|
|||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil slice constant")
|
panic("expected nil slice constant")
|
||||||
}
|
}
|
||||||
elemType := c.getLLVMType(typ.Elem())
|
llvmPtr := llvm.ConstPointerNull(c.dataPtrType)
|
||||||
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
|
||||||
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := c.ctx.ConstStruct([]llvm.Value{
|
||||||
llvmPtr, // backing array
|
llvmPtr, // backing array
|
||||||
@@ -3056,7 +3035,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
|
|||||||
|
|
||||||
// Conversion between pointers and unsafe.Pointer.
|
// Conversion between pointers and unsafe.Pointer.
|
||||||
if isPtrFrom && isPtrTo {
|
if isPtrFrom && isPtrTo {
|
||||||
return b.CreateBitCast(value, llvmTypeTo, ""), nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typeTo := typeTo.Underlying().(type) {
|
switch typeTo := typeTo.Underlying().(type) {
|
||||||
@@ -3291,11 +3270,15 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
|||||||
// Instead of a load from the global, create a bitcast of the
|
// Instead of a load from the global, create a bitcast of the
|
||||||
// function pointer itself.
|
// function pointer itself.
|
||||||
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
||||||
_, fn := b.getFunction(b.fn.Pkg.Members[name].(*ssa.Function))
|
pkg := b.fn.Pkg
|
||||||
|
if pkg == nil {
|
||||||
|
pkg = b.fn.Origin().Pkg
|
||||||
|
}
|
||||||
|
_, fn := b.getFunction(pkg.Members[name].(*ssa.Function))
|
||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
||||||
}
|
}
|
||||||
return b.CreateBitCast(fn, b.i8ptrType, ""), nil
|
return fn, nil
|
||||||
} else {
|
} else {
|
||||||
b.createNilCheck(unop.X, x, "deref")
|
b.createNilCheck(unop.X, x, "deref")
|
||||||
load := b.CreateLoad(valueType, x, "")
|
load := b.CreateLoad(valueType, x, "")
|
||||||
|
|||||||
@@ -91,14 +91,12 @@ func TestCompiler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Optimize IR a little.
|
// Optimize IR a little.
|
||||||
funcPasses := llvm.NewFunctionPassManagerForModule(mod)
|
passOptions := llvm.NewPassBuilderOptions()
|
||||||
defer funcPasses.Dispose()
|
defer passOptions.Dispose()
|
||||||
funcPasses.AddInstructionCombiningPass()
|
err = mod.RunPasses("instcombine", llvm.TargetMachine{}, passOptions)
|
||||||
funcPasses.InitializeFunc()
|
if err != nil {
|
||||||
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
t.Error(err)
|
||||||
funcPasses.RunFunc(fn)
|
|
||||||
}
|
}
|
||||||
funcPasses.FinalizeFunc()
|
|
||||||
|
|
||||||
outFilePrefix := tc.file[:len(tc.file)-3]
|
outFilePrefix := tc.file[:len(tc.file)-3]
|
||||||
if tc.target != "" {
|
if tc.target != "" {
|
||||||
@@ -169,9 +167,9 @@ func filterIrrelevantIRLines(lines []string) []string {
|
|||||||
if strings.HasPrefix(line, "source_filename = ") {
|
if strings.HasPrefix(line, "source_filename = ") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if llvmVersion < 14 && strings.HasPrefix(line, "target datalayout = ") {
|
if llvmVersion < 15 && strings.HasPrefix(line, "target datalayout = ") {
|
||||||
// The datalayout string may vary betewen LLVM versions.
|
// The datalayout string may vary betewen LLVM versions.
|
||||||
// Right now test outputs are for LLVM 14 and higher.
|
// Right now test outputs are for LLVM 15 and higher.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out = append(out, line)
|
out = append(out, line)
|
||||||
@@ -245,7 +243,7 @@ func testCompilePackage(t *testing.T, options *compileopts.Options, file string)
|
|||||||
defer machine.Dispose()
|
defer machine.Dispose()
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, "./testdata/"+file, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, "./testdata/"+file, types.Config{
|
||||||
Sizes: Sizes(machine),
|
Sizes: Sizes(machine),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+24
-33
@@ -60,9 +60,8 @@ func (b *builder) deferInitFunc() {
|
|||||||
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
|
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
|
||||||
|
|
||||||
// Create defer list pointer.
|
// Create defer list pointer.
|
||||||
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
|
||||||
b.deferPtr = b.CreateAlloca(deferType, "deferPtr")
|
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
|
||||||
b.CreateStore(llvm.ConstPointerNull(deferType), b.deferPtr)
|
|
||||||
|
|
||||||
if b.hasDeferFrame() {
|
if b.hasDeferFrame() {
|
||||||
// Set up the defer frame with the current stack pointer.
|
// Set up the defer frame with the current stack pointer.
|
||||||
@@ -249,8 +248,7 @@ func isInLoop(start *ssa.BasicBlock) bool {
|
|||||||
func (b *builder) createDefer(instr *ssa.Defer) {
|
func (b *builder) createDefer(instr *ssa.Defer) {
|
||||||
// The pointer to the previous defer struct, which we will replace to
|
// The pointer to the previous defer struct, which we will replace to
|
||||||
// make a linked list.
|
// make a linked list.
|
||||||
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
next := b.CreateLoad(b.dataPtrType, b.deferPtr, "defer.next")
|
||||||
next := b.CreateLoad(deferType, b.deferPtr, "defer.next")
|
|
||||||
|
|
||||||
var values []llvm.Value
|
var values []llvm.Value
|
||||||
valueTypes := []llvm.Type{b.uintptrType, next.Type()}
|
valueTypes := []llvm.Type{b.uintptrType, next.Type()}
|
||||||
@@ -271,7 +269,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
|||||||
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
||||||
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
||||||
values = []llvm.Value{callback, next, typecode, receiverValue}
|
values = []llvm.Value{callback, next, typecode, receiverValue}
|
||||||
valueTypes = append(valueTypes, b.i8ptrType, b.i8ptrType)
|
valueTypes = append(valueTypes, b.dataPtrType, b.dataPtrType)
|
||||||
for _, arg := range instr.Call.Args {
|
for _, arg := range instr.Call.Args {
|
||||||
val := b.getValue(arg, getPos(instr))
|
val := b.getValue(arg, getPos(instr))
|
||||||
values = append(values, val)
|
values = append(values, val)
|
||||||
@@ -391,9 +389,8 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
|||||||
// This may be hit a variable number of times, so use a heap allocation.
|
// This may be hit a variable number of times, so use a heap allocation.
|
||||||
size := b.targetData.TypeAllocSize(deferredCallType)
|
size := b.targetData.TypeAllocSize(deferredCallType)
|
||||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
nilPtr := llvm.ConstNull(b.i8ptrType)
|
nilPtr := llvm.ConstNull(b.dataPtrType)
|
||||||
allocCall := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
|
alloca = b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
|
||||||
alloca = b.CreateBitCast(allocCall, llvm.PointerType(deferredCallType, 0), "defer.alloc")
|
|
||||||
}
|
}
|
||||||
if b.NeedsStackObjects {
|
if b.NeedsStackObjects {
|
||||||
b.trackPointer(alloca)
|
b.trackPointer(alloca)
|
||||||
@@ -401,14 +398,12 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
|||||||
b.CreateStore(deferredCall, alloca)
|
b.CreateStore(deferredCall, alloca)
|
||||||
|
|
||||||
// Push it on top of the linked list by replacing deferPtr.
|
// Push it on top of the linked list by replacing deferPtr.
|
||||||
allocaCast := b.CreateBitCast(alloca, next.Type(), "defer.alloca.cast")
|
b.CreateStore(alloca, b.deferPtr)
|
||||||
b.CreateStore(allocaCast, b.deferPtr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRunDefers emits code to run all deferred functions.
|
// createRunDefers emits code to run all deferred functions.
|
||||||
func (b *builder) createRunDefers() {
|
func (b *builder) createRunDefers() {
|
||||||
deferType := b.getLLVMRuntimeType("_defer")
|
deferType := b.getLLVMRuntimeType("_defer")
|
||||||
deferPtrType := llvm.PointerType(deferType, 0)
|
|
||||||
|
|
||||||
// Add a loop like the following:
|
// Add a loop like the following:
|
||||||
// for stack != nil {
|
// for stack != nil {
|
||||||
@@ -435,7 +430,7 @@ func (b *builder) createRunDefers() {
|
|||||||
// Create loop head:
|
// Create loop head:
|
||||||
// for stack != nil {
|
// for stack != nil {
|
||||||
b.SetInsertPointAtEnd(loophead)
|
b.SetInsertPointAtEnd(loophead)
|
||||||
deferData := b.CreateLoad(deferPtrType, b.deferPtr, "")
|
deferData := b.CreateLoad(b.dataPtrType, b.deferPtr, "")
|
||||||
stackIsNil := b.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil")
|
stackIsNil := b.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil")
|
||||||
b.CreateCondBr(stackIsNil, end, loop)
|
b.CreateCondBr(stackIsNil, end, loop)
|
||||||
|
|
||||||
@@ -448,7 +443,7 @@ func (b *builder) createRunDefers() {
|
|||||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), 1, false), // .next field
|
llvm.ConstInt(b.ctx.Int32Type(), 1, false), // .next field
|
||||||
}, "stack.next.gep")
|
}, "stack.next.gep")
|
||||||
nextStack := b.CreateLoad(deferPtrType, nextStackGEP, "stack.next")
|
nextStack := b.CreateLoad(b.dataPtrType, nextStackGEP, "stack.next")
|
||||||
b.CreateStore(nextStack, b.deferPtr)
|
b.CreateStore(nextStack, b.deferPtr)
|
||||||
gep := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{
|
gep := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
@@ -469,28 +464,26 @@ func (b *builder) createRunDefers() {
|
|||||||
// Call on an value or interface value.
|
// Call on an value or interface value.
|
||||||
|
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
|
||||||
|
|
||||||
if !callback.IsInvoke() {
|
if !callback.IsInvoke() {
|
||||||
//Expect funcValue to be passed through the deferred call.
|
//Expect funcValue to be passed through the deferred call.
|
||||||
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
|
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
|
||||||
} else {
|
} else {
|
||||||
//Expect typecode
|
//Expect typecode
|
||||||
valueTypes = append(valueTypes, b.i8ptrType, b.i8ptrType)
|
valueTypes = append(valueTypes, b.dataPtrType, b.dataPtrType)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, arg := range callback.Args {
|
for _, arg := range callback.Args {
|
||||||
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
||||||
}
|
}
|
||||||
|
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
|
||||||
|
|
||||||
// Extract the params from the struct (including receiver).
|
// Extract the params from the struct (including receiver).
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
|
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||||
for i := 2; i < len(valueTypes); i++ {
|
for i := 2; i < len(valueTypes); i++ {
|
||||||
gep := b.CreateInBoundsGEP(deferredCallType, deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
|
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -505,7 +498,8 @@ func (b *builder) createRunDefers() {
|
|||||||
|
|
||||||
//Get function pointer and context
|
//Get function pointer and context
|
||||||
var context llvm.Value
|
var context llvm.Value
|
||||||
fnType, fnPtr, context = b.decodeFuncValue(funcValue, callback.Signature())
|
fnPtr, context = b.decodeFuncValue(funcValue)
|
||||||
|
fnType = b.getLLVMFunctionType(callback.Signature())
|
||||||
|
|
||||||
//Pass context
|
//Pass context
|
||||||
forwardParams = append(forwardParams, context)
|
forwardParams = append(forwardParams, context)
|
||||||
@@ -519,7 +513,7 @@ func (b *builder) createRunDefers() {
|
|||||||
// Add the context parameter. An interface call cannot also be a
|
// Add the context parameter. An interface call cannot also be a
|
||||||
// closure but we have to supply the parameter anyway for platforms
|
// closure but we have to supply the parameter anyway for platforms
|
||||||
// with a strict calling convention.
|
// with a strict calling convention.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
|
||||||
}
|
}
|
||||||
|
|
||||||
b.createCall(fnType, fnPtr, forwardParams, "")
|
b.createCall(fnType, fnPtr, forwardParams, "")
|
||||||
@@ -528,18 +522,17 @@ func (b *builder) createRunDefers() {
|
|||||||
// Direct call.
|
// Direct call.
|
||||||
|
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
|
||||||
for _, param := range getParams(callback.Signature) {
|
for _, param := range getParams(callback.Signature) {
|
||||||
valueTypes = append(valueTypes, b.getLLVMType(param.Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(param.Type()))
|
||||||
}
|
}
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
|
||||||
|
|
||||||
// Extract the params from the struct.
|
// Extract the params from the struct.
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := range getParams(callback.Signature) {
|
for i := range getParams(callback.Signature) {
|
||||||
gep := b.CreateInBoundsGEP(deferredCallType, deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
|
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -549,7 +542,7 @@ func (b *builder) createRunDefers() {
|
|||||||
if !b.getFunctionInfo(callback).exported {
|
if !b.getFunctionInfo(callback).exported {
|
||||||
// Add the context parameter. We know it is ignored by the receiving
|
// Add the context parameter. We know it is ignored by the receiving
|
||||||
// function, but we have to pass one anyway.
|
// function, but we have to pass one anyway.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call real function.
|
// Call real function.
|
||||||
@@ -559,20 +552,19 @@ func (b *builder) createRunDefers() {
|
|||||||
case *ssa.MakeClosure:
|
case *ssa.MakeClosure:
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
fn := callback.Fn.(*ssa.Function)
|
fn := callback.Fn.(*ssa.Function)
|
||||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
|
||||||
params := fn.Signature.Params()
|
params := fn.Signature.Params()
|
||||||
for i := 0; i < params.Len(); i++ {
|
for i := 0; i < params.Len(); i++ {
|
||||||
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||||
}
|
}
|
||||||
valueTypes = append(valueTypes, b.i8ptrType) // closure
|
valueTypes = append(valueTypes, b.dataPtrType) // closure
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
|
||||||
|
|
||||||
// Extract the params from the struct.
|
// Extract the params from the struct.
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 2; i < len(valueTypes); i++ {
|
for i := 2; i < len(valueTypes); i++ {
|
||||||
gep := b.CreateInBoundsGEP(deferredCallType, deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
||||||
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
|
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -584,7 +576,7 @@ func (b *builder) createRunDefers() {
|
|||||||
db := b.deferBuiltinFuncs[callback]
|
db := b.deferBuiltinFuncs[callback]
|
||||||
|
|
||||||
//Get parameter types
|
//Get parameter types
|
||||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
|
||||||
|
|
||||||
//Get signature from call results
|
//Get signature from call results
|
||||||
params := callback.Type().Underlying().(*types.Signature).Params()
|
params := callback.Type().Underlying().(*types.Signature).Params()
|
||||||
@@ -593,13 +585,12 @@ func (b *builder) createRunDefers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
|
||||||
|
|
||||||
// Extract the params from the struct.
|
// Extract the params from the struct.
|
||||||
var argValues []llvm.Value
|
var argValues []llvm.Value
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 0; i < params.Len(); i++ {
|
for i := 0; i < params.Len(); i++ {
|
||||||
gep := b.CreateInBoundsGEP(deferredCallType, deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
|
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
|
||||||
argValues = append(argValues, forwardParam)
|
argValues = append(argValues, forwardParam)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-39
@@ -13,35 +13,14 @@ import (
|
|||||||
// createFuncValue creates a function value from a raw function pointer with no
|
// createFuncValue creates a function value from a raw function pointer with no
|
||||||
// context.
|
// context.
|
||||||
func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
||||||
return b.compilerContext.createFuncValue(b.Builder, funcPtr, context, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createFuncValue creates a function value from a raw function pointer with no
|
|
||||||
// context.
|
|
||||||
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
|
||||||
// Closure is: {context, function pointer}
|
// Closure is: {context, function pointer}
|
||||||
funcValueScalar := llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
|
funcValueType := b.getFuncType(sig)
|
||||||
funcValueType := c.getFuncType(sig)
|
|
||||||
funcValue := llvm.Undef(funcValueType)
|
funcValue := llvm.Undef(funcValueType)
|
||||||
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
|
funcValue = b.CreateInsertValue(funcValue, context, 0, "")
|
||||||
funcValue = builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
|
funcValue = b.CreateInsertValue(funcValue, funcPtr, 1, "")
|
||||||
return funcValue
|
return funcValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFuncSignatureID returns a new external global for a given signature. This
|
|
||||||
// global reference is not real, it is only used during func lowering to assign
|
|
||||||
// signature types to functions and will then be removed.
|
|
||||||
func (c *compilerContext) getFuncSignatureID(sig *types.Signature) llvm.Value {
|
|
||||||
s, _ := getTypeCodeName(sig)
|
|
||||||
sigGlobalName := "reflect/types.funcid:" + s
|
|
||||||
sigGlobal := c.mod.NamedGlobal(sigGlobalName)
|
|
||||||
if sigGlobal.IsNil() {
|
|
||||||
sigGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), sigGlobalName)
|
|
||||||
sigGlobal.SetGlobalConstant(true)
|
|
||||||
}
|
|
||||||
return sigGlobal
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractFuncScalar returns some scalar that can be used in comparisons. It is
|
// extractFuncScalar returns some scalar that can be used in comparisons. It is
|
||||||
// a cheap operation.
|
// a cheap operation.
|
||||||
func (b *builder) extractFuncScalar(funcValue llvm.Value) llvm.Value {
|
func (b *builder) extractFuncScalar(funcValue llvm.Value) llvm.Value {
|
||||||
@@ -55,28 +34,20 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decodeFuncValue extracts the context and the function pointer from this func
|
// decodeFuncValue extracts the context and the function pointer from this func
|
||||||
// value. This may be an expensive operation.
|
// value.
|
||||||
func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcType llvm.Type, funcPtr, context llvm.Value) {
|
func (b *builder) decodeFuncValue(funcValue llvm.Value) (funcPtr, context llvm.Value) {
|
||||||
context = b.CreateExtractValue(funcValue, 0, "")
|
context = b.CreateExtractValue(funcValue, 0, "")
|
||||||
funcPtr = b.CreateExtractValue(funcValue, 1, "")
|
funcPtr = b.CreateExtractValue(funcValue, 1, "")
|
||||||
if !funcPtr.IsAConstantExpr().IsNil() && funcPtr.Opcode() == llvm.BitCast {
|
|
||||||
funcPtr = funcPtr.Operand(0) // needed for LLVM 14 (no opaque pointers)
|
|
||||||
}
|
|
||||||
if sig != nil {
|
|
||||||
funcType = b.getRawFuncType(sig)
|
|
||||||
llvmSig := llvm.PointerType(funcType, b.funcPtrAddrSpace)
|
|
||||||
funcPtr = b.CreateBitCast(funcPtr, llvmSig, "")
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFuncType returns the type of a func value given a signature.
|
// getFuncType returns the type of a func value given a signature.
|
||||||
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
|
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
|
||||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
|
return c.ctx.StructType([]llvm.Type{c.dataPtrType, c.funcPtrType}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRawFuncType returns a LLVM function type for a given signature.
|
// getLLVMFunctionType returns a LLVM function type for a given signature.
|
||||||
func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type {
|
||||||
// Get the return type.
|
// Get the return type.
|
||||||
var returnType llvm.Type
|
var returnType llvm.Type
|
||||||
switch typ.Results().Len() {
|
switch typ.Results().Len() {
|
||||||
@@ -104,7 +75,7 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
|||||||
if recv.StructName() == "runtime._interface" {
|
if recv.StructName() == "runtime._interface" {
|
||||||
// This is a call on an interface, not a concrete type.
|
// This is a call on an interface, not a concrete type.
|
||||||
// The receiver is not an interface, but a i8* type.
|
// The receiver is not an interface, but a i8* type.
|
||||||
recv = c.i8ptrType
|
recv = c.dataPtrType
|
||||||
}
|
}
|
||||||
for _, info := range c.expandFormalParamType(recv, "", nil) {
|
for _, info := range c.expandFormalParamType(recv, "", nil) {
|
||||||
paramTypes = append(paramTypes, info.llvmType)
|
paramTypes = append(paramTypes, info.llvmType)
|
||||||
@@ -117,7 +88,7 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// All functions take these parameters at the end.
|
// All functions take these parameters at the end.
|
||||||
paramTypes = append(paramTypes, c.i8ptrType) // context
|
paramTypes = append(paramTypes, c.dataPtrType) // context
|
||||||
|
|
||||||
// Make a func type out of the signature.
|
// Make a func type out of the signature.
|
||||||
return llvm.FunctionType(returnType, paramTypes, false)
|
return llvm.FunctionType(returnType, paramTypes, false)
|
||||||
|
|||||||
@@ -81,9 +81,6 @@ func (b *builder) trackValue(value llvm.Value) {
|
|||||||
// trackPointer creates a call to runtime.trackPointer, bitcasting the poitner
|
// trackPointer creates a call to runtime.trackPointer, bitcasting the poitner
|
||||||
// first if needed. The input value must be of LLVM pointer type.
|
// first if needed. The input value must be of LLVM pointer type.
|
||||||
func (b *builder) trackPointer(value llvm.Value) {
|
func (b *builder) trackPointer(value llvm.Value) {
|
||||||
if value.Type() != b.i8ptrType {
|
|
||||||
value = b.CreateBitCast(value, b.i8ptrType, "")
|
|
||||||
}
|
|
||||||
b.createRuntimeCall("trackPointer", []llvm.Value{value, b.stackChainAlloca}, "")
|
b.createRuntimeCall("trackPointer", []llvm.Value{value, b.stackChainAlloca}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-12
@@ -21,7 +21,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
|
|
||||||
var prefix string
|
var prefix string
|
||||||
var funcPtr llvm.Value
|
var funcPtr llvm.Value
|
||||||
var funcPtrType llvm.Type
|
var funcType llvm.Type
|
||||||
hasContext := false
|
hasContext := false
|
||||||
if callee := instr.Call.StaticCallee(); callee != nil {
|
if callee := instr.Call.StaticCallee(); callee != nil {
|
||||||
// Static callee is known. This makes it easier to start a new
|
// Static callee is known. This makes it easier to start a new
|
||||||
@@ -42,7 +42,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
params = append(params, context) // context parameter
|
params = append(params, context) // context parameter
|
||||||
hasContext = true
|
hasContext = true
|
||||||
}
|
}
|
||||||
funcPtrType, funcPtr = b.getFunction(callee)
|
funcType, funcPtr = b.getFunction(callee)
|
||||||
} else if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok {
|
} else if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok {
|
||||||
// We cheat. None of the builtins do any long or blocking operation, so
|
// We cheat. None of the builtins do any long or blocking operation, so
|
||||||
// we might as well run these builtins right away without the program
|
// we might as well run these builtins right away without the program
|
||||||
@@ -80,7 +80,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
itfTypeCode := b.CreateExtractValue(itf, 0, "")
|
itfTypeCode := b.CreateExtractValue(itf, 0, "")
|
||||||
itfValue := b.CreateExtractValue(itf, 1, "")
|
itfValue := b.CreateExtractValue(itf, 1, "")
|
||||||
funcPtr = b.getInvokeFunction(&instr.Call)
|
funcPtr = b.getInvokeFunction(&instr.Call)
|
||||||
funcPtrType = funcPtr.GlobalValueType()
|
funcType = funcPtr.GlobalValueType()
|
||||||
params = append([]llvm.Value{itfValue}, params...) // start with receiver
|
params = append([]llvm.Value{itfValue}, params...) // start with receiver
|
||||||
params = append(params, itfTypeCode) // end with typecode
|
params = append(params, itfTypeCode) // end with typecode
|
||||||
} else {
|
} else {
|
||||||
@@ -90,7 +90,8 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
// * The function context, for closures.
|
// * The function context, for closures.
|
||||||
// * The function pointer (for tasks).
|
// * The function pointer (for tasks).
|
||||||
var context llvm.Value
|
var context llvm.Value
|
||||||
funcPtrType, funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)), instr.Call.Value.Type().Underlying().(*types.Signature))
|
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)))
|
||||||
|
funcType = b.getLLVMFunctionType(instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||||
params = append(params, context, funcPtr)
|
params = append(params, context, funcPtr)
|
||||||
hasContext = true
|
hasContext = true
|
||||||
prefix = b.fn.RelString(nil)
|
prefix = b.fn.RelString(nil)
|
||||||
@@ -98,14 +99,14 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
|
|
||||||
paramBundle := b.emitPointerPack(params)
|
paramBundle := b.emitPointerPack(params)
|
||||||
var stackSize llvm.Value
|
var stackSize llvm.Value
|
||||||
callee := b.createGoroutineStartWrapper(funcPtrType, funcPtr, prefix, hasContext, instr.Pos())
|
callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, instr.Pos())
|
||||||
if b.AutomaticStackSize {
|
if b.AutomaticStackSize {
|
||||||
// The stack size is not known until after linking. Call a dummy
|
// The stack size is not known until after linking. Call a dummy
|
||||||
// function that will be replaced with a load from a special ELF
|
// function that will be replaced with a load from a special ELF
|
||||||
// section that contains the stack size (and is modified after
|
// section that contains the stack size (and is modified after
|
||||||
// linking).
|
// linking).
|
||||||
stackSizeFnType, stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
|
stackSizeFnType, stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
|
||||||
stackSize = b.createCall(stackSizeFnType, stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType)}, "stacksize")
|
stackSize = b.createCall(stackSizeFnType, stackSizeFn, []llvm.Value{callee, llvm.Undef(b.dataPtrType)}, "stacksize")
|
||||||
} else {
|
} else {
|
||||||
// The stack size is fixed at compile time. By emitting it here as a
|
// The stack size is fixed at compile time. By emitting it here as a
|
||||||
// constant, it can be optimized.
|
// constant, it can be optimized.
|
||||||
@@ -115,7 +116,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
||||||
}
|
}
|
||||||
fnType, start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
fnType, start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
||||||
b.createCall(fnType, start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType)}, "")
|
b.createCall(fnType, start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.dataPtrType)}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// createGoroutineStartWrapper creates a wrapper for the task-based
|
// createGoroutineStartWrapper creates a wrapper for the task-based
|
||||||
@@ -165,7 +166,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the wrapper.
|
// Create the wrapper.
|
||||||
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
|
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false)
|
||||||
wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
|
wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
|
||||||
c.addStandardAttributes(wrapper)
|
c.addStandardAttributes(wrapper)
|
||||||
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||||
@@ -203,7 +204,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
|||||||
}
|
}
|
||||||
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
|
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
|
||||||
if !hasContext {
|
if !hasContext {
|
||||||
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy context parameter
|
params = append(params, llvm.Undef(c.dataPtrType)) // add dummy context parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the call.
|
// Create the call.
|
||||||
@@ -211,7 +212,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
|||||||
|
|
||||||
if c.Scheduler == "asyncify" {
|
if c.Scheduler == "asyncify" {
|
||||||
b.CreateCall(deadlockType, deadlock, []llvm.Value{
|
b.CreateCall(deadlockType, deadlock, []llvm.Value{
|
||||||
llvm.Undef(c.i8ptrType),
|
llvm.Undef(c.dataPtrType),
|
||||||
}, "")
|
}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +235,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
|||||||
// merged into one.
|
// merged into one.
|
||||||
|
|
||||||
// Create the wrapper.
|
// Create the wrapper.
|
||||||
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
|
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false)
|
||||||
wrapper = llvm.AddFunction(c.mod, prefix+".gowrapper", wrapperType)
|
wrapper = llvm.AddFunction(c.mod, prefix+".gowrapper", wrapperType)
|
||||||
c.addStandardAttributes(wrapper)
|
c.addStandardAttributes(wrapper)
|
||||||
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||||
@@ -279,7 +280,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
|||||||
|
|
||||||
if c.Scheduler == "asyncify" {
|
if c.Scheduler == "asyncify" {
|
||||||
b.CreateCall(deadlockType, deadlock, []llvm.Value{
|
b.CreateCall(deadlockType, deadlock, []llvm.Value{
|
||||||
llvm.Undef(c.i8ptrType),
|
llvm.Undef(c.dataPtrType),
|
||||||
}, "")
|
}, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
case llvm.IntegerTypeKind:
|
case llvm.IntegerTypeKind:
|
||||||
constraints = append(constraints, "r")
|
constraints = append(constraints, "r")
|
||||||
case llvm.PointerTypeKind:
|
case llvm.PointerTypeKind:
|
||||||
// Memory references require a type in LLVM 14, probably as a
|
// Memory references require a type starting with LLVM 14,
|
||||||
// preparation for opaque pointers.
|
// probably as a preparation for opaque pointers.
|
||||||
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
|
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
|
||||||
return s
|
return s
|
||||||
default:
|
default:
|
||||||
|
|||||||
+34
-26
@@ -124,16 +124,19 @@ func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
|
|||||||
func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||||
ms := c.program.MethodSets.MethodSet(typ)
|
ms := c.program.MethodSets.MethodSet(typ)
|
||||||
hasMethodSet := ms.Len() != 0
|
hasMethodSet := ms.Len() != 0
|
||||||
if _, ok := typ.Underlying().(*types.Interface); ok {
|
_, isInterface := typ.Underlying().(*types.Interface)
|
||||||
|
if isInterface {
|
||||||
hasMethodSet = false
|
hasMethodSet = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As defined in https://pkg.go.dev/reflect#Type:
|
||||||
|
// NumMethod returns the number of methods accessible using Method.
|
||||||
|
// 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
|
var numMethods int
|
||||||
if hasMethodSet {
|
for i := 0; i < ms.Len(); i++ {
|
||||||
for i := 0; i < ms.Len(); i++ {
|
if isInterface || ms.At(i).Obj().Exported() {
|
||||||
if ms.At(i).Obj().Exported() {
|
numMethods++
|
||||||
numMethods++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,10 +417,10 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||||||
}, typeFields...)
|
}, typeFields...)
|
||||||
if hasMethodSet {
|
if hasMethodSet {
|
||||||
typeFields = append([]llvm.Value{
|
typeFields = append([]llvm.Value{
|
||||||
llvm.ConstBitCast(c.getTypeMethodSet(typ), c.i8ptrType),
|
c.getTypeMethodSet(typ),
|
||||||
}, typeFields...)
|
}, typeFields...)
|
||||||
}
|
}
|
||||||
alignment := c.targetData.TypeAllocSize(c.i8ptrType)
|
alignment := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||||
if alignment < 4 {
|
if alignment < 4 {
|
||||||
alignment = 4
|
alignment = 4
|
||||||
}
|
}
|
||||||
@@ -511,8 +514,7 @@ var basicTypeNames = [...]string{
|
|||||||
func getTypeCodeName(t types.Type) (string, bool) {
|
func getTypeCodeName(t types.Type) (string, bool) {
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
// Note: check for `t.Obj().Pkg() != nil` for Go 1.18 only.
|
if t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
||||||
if t.Obj().Pkg() != nil && t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
|
||||||
return "named:" + t.String() + "$local", true
|
return "named:" + t.String() + "$local", true
|
||||||
}
|
}
|
||||||
return "named:" + t.String(), false
|
return "named:" + t.String(), false
|
||||||
@@ -628,7 +630,7 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
|||||||
// Construct global value.
|
// Construct global value.
|
||||||
globalValue := c.ctx.ConstStruct([]llvm.Value{
|
globalValue := c.ctx.ConstStruct([]llvm.Value{
|
||||||
llvm.ConstInt(c.uintptrType, uint64(ms.Len()), false),
|
llvm.ConstInt(c.uintptrType, uint64(ms.Len()), false),
|
||||||
llvm.ConstArray(c.i8ptrType, signatures),
|
llvm.ConstArray(c.dataPtrType, signatures),
|
||||||
c.ctx.ConstStruct(wrappers, false),
|
c.ctx.ConstStruct(wrappers, false),
|
||||||
}, false)
|
}, false)
|
||||||
global = llvm.AddGlobal(c.mod, globalValue.Type(), globalName)
|
global = llvm.AddGlobal(c.mod, globalValue.Type(), globalName)
|
||||||
@@ -684,19 +686,25 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
|
|
||||||
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
||||||
commaOk := llvm.Value{}
|
commaOk := llvm.Value{}
|
||||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
|
||||||
// Type assert on interface type.
|
|
||||||
// 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}, "")
|
|
||||||
|
|
||||||
|
if intf, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||||
|
if intf.Empty() {
|
||||||
|
// intf is the empty interface => no methods
|
||||||
|
// 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}, "")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
name, _ := getTypeCodeName(expr.AssertedType)
|
name, _ := getTypeCodeName(expr.AssertedType)
|
||||||
globalName := "reflect/types.typeid:" + name
|
globalName := "reflect/types.typeid:" + name
|
||||||
@@ -779,7 +787,7 @@ func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) ll
|
|||||||
fnName := s + ".$typeassert"
|
fnName := s + ".$typeassert"
|
||||||
llvmFn := c.mod.NamedFunction(fnName)
|
llvmFn := c.mod.NamedFunction(fnName)
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.i8ptrType}, false)
|
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
|
||||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||||
c.addStandardDeclaredAttributes(llvmFn)
|
c.addStandardDeclaredAttributes(llvmFn)
|
||||||
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
|
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
|
||||||
@@ -802,7 +810,7 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
|||||||
paramTuple = append(paramTuple, sig.Params().At(i))
|
paramTuple = append(paramTuple, sig.Params().At(i))
|
||||||
}
|
}
|
||||||
paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer]))
|
paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer]))
|
||||||
llvmFnType := c.getRawFuncType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false))
|
llvmFnType := c.getLLVMFunctionType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false))
|
||||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||||
c.addStandardDeclaredAttributes(llvmFn)
|
c.addStandardDeclaredAttributes(llvmFn)
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-invoke", c.getMethodSignatureName(instr.Method)))
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-invoke", c.getMethodSignatureName(instr.Method)))
|
||||||
@@ -842,7 +850,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create wrapper function
|
// create wrapper function
|
||||||
paramTypes := append([]llvm.Type{c.i8ptrType}, llvmFnType.ParamTypes()[len(expandedReceiverType):]...)
|
paramTypes := append([]llvm.Type{c.dataPtrType}, llvmFnType.ParamTypes()[len(expandedReceiverType):]...)
|
||||||
wrapFnType := llvm.FunctionType(llvmFnType.ReturnType(), paramTypes, false)
|
wrapFnType := llvm.FunctionType(llvmFnType.ReturnType(), paramTypes, false)
|
||||||
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
||||||
c.addStandardAttributes(wrapper)
|
c.addStandardAttributes(wrapper)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
|
|||||||
// Fall back to a generic error.
|
// Fall back to a generic error.
|
||||||
return llvm.Value{}, b.makeError(instr.Pos(), "interrupt function must be constant")
|
return llvm.Value{}, b.makeError(instr.Pos(), "interrupt function must be constant")
|
||||||
}
|
}
|
||||||
_, funcRawPtr, funcContext := b.decodeFuncValue(funcValue, nil)
|
funcRawPtr, funcContext := b.decodeFuncValue(funcValue)
|
||||||
funcPtr := llvm.ConstPtrToInt(funcRawPtr, b.uintptrType)
|
funcPtr := llvm.ConstPtrToInt(funcRawPtr, b.uintptrType)
|
||||||
|
|
||||||
// Create a new global of type runtime/interrupt.handle. Globals of this
|
// Create a new global of type runtime/interrupt.handle. Globals of this
|
||||||
|
|||||||
+13
-10
@@ -7,7 +7,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +23,8 @@ func (b *builder) defineIntrinsicFunction() {
|
|||||||
b.createMemoryCopyImpl()
|
b.createMemoryCopyImpl()
|
||||||
case name == "runtime.memzero":
|
case name == "runtime.memzero":
|
||||||
b.createMemoryZeroImpl()
|
b.createMemoryZeroImpl()
|
||||||
|
case name == "runtime.stacksave":
|
||||||
|
b.createStackSaveImpl()
|
||||||
case name == "runtime.KeepAlive":
|
case name == "runtime.KeepAlive":
|
||||||
b.createKeepAliveImpl()
|
b.createKeepAliveImpl()
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||||
@@ -48,12 +49,9 @@ func (b *builder) defineIntrinsicFunction() {
|
|||||||
func (b *builder) createMemoryCopyImpl() {
|
func (b *builder) createMemoryCopyImpl() {
|
||||||
b.createFunctionStart(true)
|
b.createFunctionStart(true)
|
||||||
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||||
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
|
||||||
fnName = "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
|
||||||
}
|
|
||||||
llvmFn := b.mod.NamedFunction(fnName)
|
llvmFn := b.mod.NamedFunction(fnName)
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.i8ptrType, b.uintptrType, b.ctx.Int1Type()}, false)
|
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType, b.dataPtrType, b.uintptrType, b.ctx.Int1Type()}, false)
|
||||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
||||||
}
|
}
|
||||||
var params []llvm.Value
|
var params []llvm.Value
|
||||||
@@ -81,15 +79,20 @@ func (b *builder) createMemoryZeroImpl() {
|
|||||||
b.CreateRetVoid()
|
b.CreateRetVoid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createStackSaveImpl creates a call to llvm.stacksave.p0 to read the current
|
||||||
|
// stack pointer.
|
||||||
|
func (b *builder) createStackSaveImpl() {
|
||||||
|
b.createFunctionStart(true)
|
||||||
|
sp := b.readStackPointer()
|
||||||
|
b.CreateRet(sp)
|
||||||
|
}
|
||||||
|
|
||||||
// Return the llvm.memset.p0.i8 function declaration.
|
// Return the llvm.memset.p0.i8 function declaration.
|
||||||
func (c *compilerContext) getMemsetFunc() llvm.Value {
|
func (c *compilerContext) getMemsetFunc() llvm.Value {
|
||||||
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||||
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
|
||||||
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
|
||||||
}
|
|
||||||
llvmFn := c.mod.NamedFunction(fnName)
|
llvmFn := c.mod.NamedFunction(fnName)
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
|
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
|
||||||
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
|
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
|
||||||
}
|
}
|
||||||
return llvmFn
|
return llvmFn
|
||||||
@@ -111,7 +114,7 @@ func (b *builder) createKeepAliveImpl() {
|
|||||||
//
|
//
|
||||||
// It should be portable to basically everything as the "r" register type
|
// It should be portable to basically everything as the "r" register type
|
||||||
// exists basically everywhere.
|
// exists basically everywhere.
|
||||||
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType}, false)
|
asmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
|
||||||
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
|
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
|
||||||
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||||
|
|
||||||
|
|||||||
+45
-46
@@ -20,7 +20,7 @@ import (
|
|||||||
//
|
//
|
||||||
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
||||||
// end the lifetime using emitLifetimeEnd after you're done with it.
|
// end the lifetime using emitLifetimeEnd after you're done with it.
|
||||||
func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, size llvm.Value) {
|
||||||
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name)
|
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,47 +63,45 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
|
|||||||
// Allocate memory for the packed data.
|
// Allocate memory for the packed data.
|
||||||
size := b.targetData.TypeAllocSize(packedType)
|
size := b.targetData.TypeAllocSize(packedType)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return llvm.ConstPointerNull(b.i8ptrType)
|
return llvm.ConstPointerNull(b.dataPtrType)
|
||||||
} else if len(values) == 1 && values[0].Type().TypeKind() == llvm.PointerTypeKind {
|
} else if len(values) == 1 && values[0].Type().TypeKind() == llvm.PointerTypeKind {
|
||||||
return b.CreateBitCast(values[0], b.i8ptrType, "pack.ptr")
|
return values[0]
|
||||||
} else if size <= b.targetData.TypeAllocSize(b.i8ptrType) {
|
} else if size <= b.targetData.TypeAllocSize(b.dataPtrType) {
|
||||||
// Packed data fits in a pointer, so store it directly inside the
|
// Packed data fits in a pointer, so store it directly inside the
|
||||||
// pointer.
|
// pointer.
|
||||||
if len(values) == 1 && values[0].Type().TypeKind() == llvm.IntegerTypeKind {
|
if len(values) == 1 && values[0].Type().TypeKind() == llvm.IntegerTypeKind {
|
||||||
// Try to keep this cast in SSA form.
|
// Try to keep this cast in SSA form.
|
||||||
return b.CreateIntToPtr(values[0], b.i8ptrType, "pack.int")
|
return b.CreateIntToPtr(values[0], b.dataPtrType, "pack.int")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because packedType is a struct and we have to cast it to a *i8, store
|
// Because packedType is a struct and we have to cast it to a *i8, store
|
||||||
// it in a *i8 alloca first and load the *i8 value from there. This is
|
// it in a *i8 alloca first and load the *i8 value from there. This is
|
||||||
// effectively a bitcast.
|
// effectively a bitcast.
|
||||||
packedAlloc, _, _ := b.createTemporaryAlloca(b.i8ptrType, "")
|
packedAlloc, _ := b.createTemporaryAlloca(b.dataPtrType, "")
|
||||||
|
|
||||||
if size < b.targetData.TypeAllocSize(b.i8ptrType) {
|
if size < b.targetData.TypeAllocSize(b.dataPtrType) {
|
||||||
// The alloca is bigger than the value that will be stored in it.
|
// The alloca is bigger than the value that will be stored in it.
|
||||||
// To avoid having some bits undefined, zero the alloca first.
|
// To avoid having some bits undefined, zero the alloca first.
|
||||||
// Hopefully this will get optimized away.
|
// Hopefully this will get optimized away.
|
||||||
b.CreateStore(llvm.ConstNull(b.i8ptrType), packedAlloc)
|
b.CreateStore(llvm.ConstNull(b.dataPtrType), packedAlloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store all values in the alloca.
|
// Store all values in the alloca.
|
||||||
packedAllocCast := b.CreateBitCast(packedAlloc, llvm.PointerType(packedType, 0), "")
|
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
indices := []llvm.Value{
|
indices := []llvm.Value{
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
|
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
|
||||||
}
|
}
|
||||||
gep := b.CreateInBoundsGEP(packedType, packedAllocCast, indices, "")
|
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
|
||||||
b.CreateStore(value, gep)
|
b.CreateStore(value, gep)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load value (the *i8) from the alloca.
|
// Load value (the *i8) from the alloca.
|
||||||
result := b.CreateLoad(b.i8ptrType, packedAlloc, "")
|
result := b.CreateLoad(b.dataPtrType, packedAlloc, "")
|
||||||
|
|
||||||
// End the lifetime of the alloca, to help the optimizer.
|
// End the lifetime of the alloca, to help the optimizer.
|
||||||
packedPtr := b.CreateBitCast(packedAlloc, b.i8ptrType, "")
|
|
||||||
packedSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(packedAlloc.Type()), false)
|
packedSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(packedAlloc.Type()), false)
|
||||||
b.emitLifetimeEnd(packedPtr, packedSize)
|
b.emitLifetimeEnd(packedAlloc, packedSize)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
} else {
|
} else {
|
||||||
@@ -124,21 +122,20 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
|
|||||||
global.SetGlobalConstant(true)
|
global.SetGlobalConstant(true)
|
||||||
global.SetUnnamedAddr(true)
|
global.SetUnnamedAddr(true)
|
||||||
global.SetLinkage(llvm.InternalLinkage)
|
global.SetLinkage(llvm.InternalLinkage)
|
||||||
return llvm.ConstBitCast(global, b.i8ptrType)
|
return global
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packed data is bigger than a pointer, so allocate it on the heap.
|
// Packed data is bigger than a pointer, so allocate it on the heap.
|
||||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
alloc := b.mod.NamedFunction("runtime.alloc")
|
alloc := b.mod.NamedFunction("runtime.alloc")
|
||||||
packedHeapAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
|
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
|
||||||
sizeValue,
|
sizeValue,
|
||||||
llvm.ConstNull(b.i8ptrType),
|
llvm.ConstNull(b.dataPtrType),
|
||||||
llvm.Undef(b.i8ptrType), // unused context parameter
|
llvm.Undef(b.dataPtrType), // unused context parameter
|
||||||
}, "")
|
}, "")
|
||||||
if b.NeedsStackObjects {
|
if b.NeedsStackObjects {
|
||||||
b.trackPointer(packedHeapAlloc)
|
b.trackPointer(packedAlloc)
|
||||||
}
|
}
|
||||||
packedAlloc := b.CreateBitCast(packedHeapAlloc, llvm.PointerType(packedType, 0), "")
|
|
||||||
|
|
||||||
// Store all values in the heap pointer.
|
// Store all values in the heap pointer.
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
@@ -151,7 +148,7 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the original heap allocation pointer, which already is an *i8.
|
// Return the original heap allocation pointer, which already is an *i8.
|
||||||
return packedHeapAlloc
|
return packedAlloc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,28 +157,27 @@ func (b *builder) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []ll
|
|||||||
packedType := b.ctx.StructType(valueTypes, false)
|
packedType := b.ctx.StructType(valueTypes, false)
|
||||||
|
|
||||||
// Get a correctly-typed pointer to the packed data.
|
// Get a correctly-typed pointer to the packed data.
|
||||||
var packedAlloc, packedRawAlloc llvm.Value
|
var packedAlloc llvm.Value
|
||||||
|
needsLifetimeEnd := false
|
||||||
size := b.targetData.TypeAllocSize(packedType)
|
size := b.targetData.TypeAllocSize(packedType)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// No data to unpack.
|
// No data to unpack.
|
||||||
} else if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.PointerTypeKind {
|
} else if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.PointerTypeKind {
|
||||||
// A single pointer is always stored directly.
|
// A single pointer is always stored directly.
|
||||||
return []llvm.Value{b.CreateBitCast(ptr, valueTypes[0], "unpack.ptr")}
|
return []llvm.Value{ptr}
|
||||||
} else if size <= b.targetData.TypeAllocSize(b.i8ptrType) {
|
} else if size <= b.targetData.TypeAllocSize(b.dataPtrType) {
|
||||||
// Packed data stored directly in pointer.
|
// Packed data stored directly in pointer.
|
||||||
if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.IntegerTypeKind {
|
if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.IntegerTypeKind {
|
||||||
// Keep this cast in SSA form.
|
// Keep this cast in SSA form.
|
||||||
return []llvm.Value{b.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
|
return []llvm.Value{b.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
|
||||||
}
|
}
|
||||||
// Fallback: load it using an alloca.
|
// Fallback: load it using an alloca.
|
||||||
packedRawAlloc, _, _ = b.createTemporaryAlloca(llvm.PointerType(b.i8ptrType, 0), "unpack.raw.alloc")
|
packedAlloc, _ = b.createTemporaryAlloca(b.dataPtrType, "unpack.raw.alloc")
|
||||||
packedRawValue := b.CreateBitCast(ptr, llvm.PointerType(b.i8ptrType, 0), "unpack.raw.value")
|
b.CreateStore(ptr, packedAlloc)
|
||||||
b.CreateStore(packedRawValue, packedRawAlloc)
|
needsLifetimeEnd = true
|
||||||
packedAlloc = b.CreateBitCast(packedRawAlloc, llvm.PointerType(packedType, 0), "unpack.alloc")
|
|
||||||
} else {
|
} else {
|
||||||
// Packed data stored on the heap. Bitcast the passed-in pointer to the
|
// Packed data stored on the heap.
|
||||||
// correct pointer type.
|
packedAlloc = ptr
|
||||||
packedAlloc = b.CreateBitCast(ptr, llvm.PointerType(packedType, 0), "unpack.raw.ptr")
|
|
||||||
}
|
}
|
||||||
// Load each value from the packed data.
|
// Load each value from the packed data.
|
||||||
values := make([]llvm.Value, len(valueTypes))
|
values := make([]llvm.Value, len(valueTypes))
|
||||||
@@ -198,10 +194,9 @@ func (b *builder) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []ll
|
|||||||
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
|
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
|
||||||
values[i] = b.CreateLoad(valueType, gep, "")
|
values[i] = b.CreateLoad(valueType, gep, "")
|
||||||
}
|
}
|
||||||
if !packedRawAlloc.IsNil() {
|
if needsLifetimeEnd {
|
||||||
allocPtr := b.CreateBitCast(packedRawAlloc, b.i8ptrType, "")
|
|
||||||
allocSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(b.uintptrType), false)
|
allocSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(b.uintptrType), false)
|
||||||
b.emitLifetimeEnd(allocPtr, allocSize)
|
b.emitLifetimeEnd(packedAlloc, allocSize)
|
||||||
}
|
}
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
@@ -253,12 +248,12 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
// Do a few checks to see whether we need to generate any object layout
|
// Do a few checks to see whether we need to generate any object layout
|
||||||
// information at all.
|
// information at all.
|
||||||
objectSizeBytes := c.targetData.TypeAllocSize(t)
|
objectSizeBytes := c.targetData.TypeAllocSize(t)
|
||||||
pointerSize := c.targetData.TypeAllocSize(c.i8ptrType)
|
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||||
pointerAlignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
|
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||||
if objectSizeBytes < pointerSize {
|
if objectSizeBytes < pointerSize {
|
||||||
// Too small to contain a pointer.
|
// Too small to contain a pointer.
|
||||||
layout := (uint64(1) << 1) | 1
|
layout := (uint64(1) << 1) | 1
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.i8ptrType)
|
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||||
}
|
}
|
||||||
bitmap := c.getPointerBitmap(t, pos)
|
bitmap := c.getPointerBitmap(t, pos)
|
||||||
if bitmap.BitLen() == 0 {
|
if bitmap.BitLen() == 0 {
|
||||||
@@ -266,13 +261,13 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
// TODO: this can be done in many other cases, e.g. when allocating an
|
// TODO: this can be done in many other cases, e.g. when allocating an
|
||||||
// array (like [4][]byte, which repeats a slice 4 times).
|
// array (like [4][]byte, which repeats a slice 4 times).
|
||||||
layout := (uint64(1) << 1) | 1
|
layout := (uint64(1) << 1) | 1
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.i8ptrType)
|
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||||
}
|
}
|
||||||
if objectSizeBytes%uint64(pointerAlignment) != 0 {
|
if objectSizeBytes%uint64(pointerAlignment) != 0 {
|
||||||
// This shouldn't happen except for packed structs, which aren't
|
// This shouldn't happen except for packed structs, which aren't
|
||||||
// currently used.
|
// currently used.
|
||||||
c.addError(pos, "internal error: unexpected object size for object with pointer field")
|
c.addError(pos, "internal error: unexpected object size for object with pointer field")
|
||||||
return llvm.ConstNull(c.i8ptrType)
|
return llvm.ConstNull(c.dataPtrType)
|
||||||
}
|
}
|
||||||
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
|
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
|
||||||
|
|
||||||
@@ -297,7 +292,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
// The runtime knows that if the least significant bit of the pointer is
|
// The runtime knows that if the least significant bit of the pointer is
|
||||||
// set, the pointer contains the value itself.
|
// set, the pointer contains the value itself.
|
||||||
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
|
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
|
||||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.i8ptrType)
|
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfortunately, the object layout is too big to fit in a pointer-sized
|
// Unfortunately, the object layout is too big to fit in a pointer-sized
|
||||||
@@ -308,7 +303,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
|
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
|
||||||
global := c.mod.NamedGlobal(globalName)
|
global := c.mod.NamedGlobal(globalName)
|
||||||
if !global.IsNil() {
|
if !global.IsNil() {
|
||||||
return llvm.ConstBitCast(global, c.i8ptrType)
|
return global
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the global initializer.
|
// Create the global initializer.
|
||||||
@@ -359,13 +354,13 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
|||||||
global.AddMetadata(0, diglobal)
|
global.AddMetadata(0, diglobal)
|
||||||
}
|
}
|
||||||
|
|
||||||
return llvm.ConstBitCast(global, c.i8ptrType)
|
return global
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||||
// bigint at the word offset that contains a pointer. This scan is recursive.
|
// bigint at the word offset that contains a pointer. This scan is recursive.
|
||||||
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
|
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
|
||||||
alignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
|
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||||
switch typ.TypeKind() {
|
switch typ.TypeKind() {
|
||||||
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
@@ -378,7 +373,7 @@ func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.In
|
|||||||
// of type uintptr, but before the LowerFuncValues pass it actually
|
// of type uintptr, but before the LowerFuncValues pass it actually
|
||||||
// contains a pointer (ptrtoint) to a global. This trips up the
|
// contains a pointer (ptrtoint) to a global. This trips up the
|
||||||
// interp package. Therefore, make the id field a pointer for now.
|
// interp package. Therefore, make the id field a pointer for now.
|
||||||
typ = c.ctx.StructType([]llvm.Type{c.i8ptrType, c.i8ptrType}, false)
|
typ = c.ctx.StructType([]llvm.Type{c.dataPtrType, c.dataPtrType}, false)
|
||||||
}
|
}
|
||||||
for i, subtyp := range typ.StructElementTypes() {
|
for i, subtyp := range typ.StructElementTypes() {
|
||||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
subptrs := c.getPointerBitmap(subtyp, pos)
|
||||||
@@ -456,10 +451,14 @@ func (c *compilerContext) isThumb() bool {
|
|||||||
// readStackPointer emits a LLVM intrinsic call that returns the current stack
|
// readStackPointer emits a LLVM intrinsic call that returns the current stack
|
||||||
// pointer as an *i8.
|
// pointer as an *i8.
|
||||||
func (b *builder) readStackPointer() llvm.Value {
|
func (b *builder) readStackPointer() llvm.Value {
|
||||||
stacksave := b.mod.NamedFunction("llvm.stacksave")
|
name := "llvm.stacksave.p0"
|
||||||
|
if llvmutil.Version() < 18 {
|
||||||
|
name = "llvm.stacksave" // backwards compatibility with LLVM 17 and below
|
||||||
|
}
|
||||||
|
stacksave := b.mod.NamedFunction(name)
|
||||||
if stacksave.IsNil() {
|
if stacksave.IsNil() {
|
||||||
fnType := llvm.FunctionType(b.i8ptrType, nil, false)
|
fnType := llvm.FunctionType(b.dataPtrType, nil, false)
|
||||||
stacksave = llvm.AddFunction(b.mod, "llvm.stacksave", fnType)
|
stacksave = llvm.AddFunction(b.mod, name, fnType)
|
||||||
}
|
}
|
||||||
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
|
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-34
@@ -1,5 +1,5 @@
|
|||||||
// Package llvmutil contains utility functions used across multiple compiler
|
// Package llvmutil contains utility functions used across multiple compiler
|
||||||
// packages. For example, they may be used by both the compiler pacakge and
|
// packages. For example, they may be used by both the compiler package and
|
||||||
// transformation packages.
|
// transformation packages.
|
||||||
//
|
//
|
||||||
// Normally, utility packages are avoided. However, in this case, the utility
|
// Normally, utility packages are avoided. However, in this case, the utility
|
||||||
@@ -14,16 +14,6 @@ import (
|
|||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Major returns the LLVM major version.
|
|
||||||
func Major() int {
|
|
||||||
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
|
|
||||||
if err != nil {
|
|
||||||
// sanity check, should be unreachable
|
|
||||||
panic("could not parse LLVM version: " + err.Error())
|
|
||||||
}
|
|
||||||
return llvmMajor
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateEntryBlockAlloca creates a new alloca in the entry block, even though
|
// CreateEntryBlockAlloca creates a new alloca in the entry block, even though
|
||||||
// the IR builder is located elsewhere. It assumes that the insert point is
|
// the IR builder is located elsewhere. It assumes that the insert point is
|
||||||
// at the end of the current block.
|
// at the end of the current block.
|
||||||
@@ -41,21 +31,19 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateTemporaryAlloca creates a new alloca in the entry block and adds
|
// CreateTemporaryAlloca creates a new alloca in the entry block and adds
|
||||||
// lifetime start infromation in the IR signalling that the alloca won't be used
|
// lifetime start information in the IR signalling that the alloca won't be used
|
||||||
// before this point.
|
// before this point.
|
||||||
//
|
//
|
||||||
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
||||||
// end the lifetime using emitLifetimeEnd after you're done with it.
|
// end the lifetime using emitLifetimeEnd after you're done with it.
|
||||||
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, size llvm.Value) {
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
|
||||||
alloca = CreateEntryBlockAlloca(builder, t, name)
|
alloca = CreateEntryBlockAlloca(builder, t, name)
|
||||||
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
|
||||||
size = llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
|
size = llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
|
||||||
fnType, fn := getLifetimeStartFunc(mod)
|
fnType, fn := getLifetimeStartFunc(mod)
|
||||||
builder.CreateCall(fnType, fn, []llvm.Value{size, bitcast}, "")
|
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,21 +52,19 @@ func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type,
|
|||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
|
||||||
|
|
||||||
alloca := CreateEntryBlockAlloca(builder, t, name)
|
alloca := CreateEntryBlockAlloca(builder, t, name)
|
||||||
builder.SetInsertPointBefore(inst)
|
builder.SetInsertPointBefore(inst)
|
||||||
bitcast := builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
|
||||||
size := llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
|
size := llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
|
||||||
fnType, fn := getLifetimeStartFunc(mod)
|
fnType, fn := getLifetimeStartFunc(mod)
|
||||||
builder.CreateCall(fnType, fn, []llvm.Value{size, bitcast}, "")
|
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
|
||||||
if next := llvm.NextInstruction(inst); !next.IsNil() {
|
if next := llvm.NextInstruction(inst); !next.IsNil() {
|
||||||
builder.SetInsertPointBefore(next)
|
builder.SetInsertPointBefore(next)
|
||||||
} else {
|
} else {
|
||||||
builder.SetInsertPointAtEnd(inst.InstructionParent())
|
builder.SetInsertPointAtEnd(inst.InstructionParent())
|
||||||
}
|
}
|
||||||
fnType, fn = getLifetimeEndFunc(mod)
|
fnType, fn = getLifetimeEndFunc(mod)
|
||||||
builder.CreateCall(fnType, fn, []llvm.Value{size, bitcast}, "")
|
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
|
||||||
return alloca
|
return alloca
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,13 +80,10 @@ func EmitLifetimeEnd(builder llvm.Builder, mod llvm.Module, ptr, size llvm.Value
|
|||||||
// first if it doesn't exist yet.
|
// first if it doesn't exist yet.
|
||||||
func getLifetimeStartFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
|
func getLifetimeStartFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
|
||||||
fnName := "llvm.lifetime.start.p0"
|
fnName := "llvm.lifetime.start.p0"
|
||||||
if Major() < 15 { // compatibility with LLVM 14
|
|
||||||
fnName = "llvm.lifetime.start.p0i8"
|
|
||||||
}
|
|
||||||
fn := mod.NamedFunction(fnName)
|
fn := mod.NamedFunction(fnName)
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
|
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), ptrType}, false)
|
||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
fn = llvm.AddFunction(mod, fnName, fnType)
|
fn = llvm.AddFunction(mod, fnName, fnType)
|
||||||
}
|
}
|
||||||
@@ -111,13 +94,10 @@ func getLifetimeStartFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
|
|||||||
// first if it doesn't exist yet.
|
// first if it doesn't exist yet.
|
||||||
func getLifetimeEndFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
|
func getLifetimeEndFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
|
||||||
fnName := "llvm.lifetime.end.p0"
|
fnName := "llvm.lifetime.end.p0"
|
||||||
if Major() < 15 {
|
|
||||||
fnName = "llvm.lifetime.end.p0i8"
|
|
||||||
}
|
|
||||||
fn := mod.NamedFunction(fnName)
|
fn := mod.NamedFunction(fnName)
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
|
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), ptrType}, false)
|
||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
fn = llvm.AddFunction(mod, fnName, fnType)
|
fn = llvm.AddFunction(mod, fnName, fnType)
|
||||||
}
|
}
|
||||||
@@ -196,7 +176,7 @@ func SplitBasicBlock(builder llvm.Builder, afterInst llvm.Value, insertAfter llv
|
|||||||
return newBlock
|
return newBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the given values to a global array like llvm.used. The global might
|
// AppendToGlobal appends the given values to a global array like llvm.used. The global might
|
||||||
// not exist yet. The values can be any pointer type, they will be cast to i8*.
|
// not exist yet. The values can be any pointer type, they will be cast to i8*.
|
||||||
func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
|
func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
|
||||||
// Read the existing values in the llvm.used array (if it exists).
|
// Read the existing values in the llvm.used array (if it exists).
|
||||||
@@ -213,14 +193,26 @@ func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the new values.
|
// Add the new values.
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
usedValues = append(usedValues, llvm.ConstPointerCast(value, i8ptrType))
|
// Note: the bitcast is necessary to cast AVR function pointers to
|
||||||
|
// address space 0 pointer types.
|
||||||
|
usedValues = append(usedValues, llvm.ConstPointerCast(value, ptrType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new array (with the old and new values).
|
// Create a new array (with the old and new values).
|
||||||
usedInitializer := llvm.ConstArray(i8ptrType, usedValues)
|
usedInitializer := llvm.ConstArray(ptrType, usedValues)
|
||||||
used := llvm.AddGlobal(mod, usedInitializer.Type(), globalName)
|
used := llvm.AddGlobal(mod, usedInitializer.Type(), globalName)
|
||||||
used.SetInitializer(usedInitializer)
|
used.SetInitializer(usedInitializer)
|
||||||
used.SetLinkage(llvm.AppendingLinkage)
|
used.SetLinkage(llvm.AppendingLinkage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the LLVM major version.
|
||||||
|
func Version() int {
|
||||||
|
majorStr := strings.Split(llvm.Version, ".")[0]
|
||||||
|
major, err := strconv.Atoi(majorStr)
|
||||||
|
if err != nil {
|
||||||
|
panic("unexpected error while parsing LLVM version: " + err.Error()) // should not happen
|
||||||
|
}
|
||||||
|
return major
|
||||||
|
}
|
||||||
|
|||||||
+23
-30
@@ -65,7 +65,7 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
|||||||
// Allocate the memory for the resulting type. Do not zero this memory: it
|
// Allocate the memory for the resulting type. Do not zero this memory: it
|
||||||
// will be zeroed by the hashmap get implementation if the key is not
|
// will be zeroed by the hashmap get implementation if the key is not
|
||||||
// present in the map.
|
// present in the map.
|
||||||
mapValueAlloca, mapValuePtr, mapValueAllocaSize := b.createTemporaryAlloca(llvmValueType, "hashmap.value")
|
mapValueAlloca, mapValueAllocaSize := b.createTemporaryAlloca(llvmValueType, "hashmap.value")
|
||||||
|
|
||||||
// We need the map size (with type uintptr) to pass to the hashmap*Get
|
// We need the map size (with type uintptr) to pass to the hashmap*Get
|
||||||
// functions. This is necessary because those *Get functions are valid on
|
// functions. This is necessary because those *Get functions are valid on
|
||||||
@@ -82,19 +82,19 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
|||||||
keyType = keyType.Underlying()
|
keyType = keyType.Underlying()
|
||||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
// key is a string
|
// key is a string
|
||||||
params := []llvm.Value{m, key, mapValuePtr, mapValueSize}
|
params := []llvm.Value{m, key, mapValueAlloca, mapValueSize}
|
||||||
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
|
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
// key can be compared with runtime.memequal
|
// key can be compared with runtime.memequal
|
||||||
// Store the key in an alloca, in the entry block to avoid dynamic stack
|
// Store the key in an alloca, in the entry block to avoid dynamic stack
|
||||||
// growth.
|
// growth.
|
||||||
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
b.CreateStore(key, mapKeyAlloca)
|
b.CreateStore(key, mapKeyAlloca)
|
||||||
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
|
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
|
||||||
// Fetch the value from the hashmap.
|
// Fetch the value from the hashmap.
|
||||||
params := []llvm.Value{m, mapKeyPtr, mapValuePtr, mapValueSize}
|
params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize}
|
||||||
commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
|
commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
|
||||||
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
|
||||||
} else {
|
} else {
|
||||||
// Not trivially comparable using memcmp. Make it an interface instead.
|
// Not trivially comparable using memcmp. Make it an interface instead.
|
||||||
itfKey := key
|
itfKey := key
|
||||||
@@ -102,14 +102,14 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
|||||||
// Not already an interface, so convert it to an interface now.
|
// Not already an interface, so convert it to an interface now.
|
||||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||||
}
|
}
|
||||||
params := []llvm.Value{m, itfKey, mapValuePtr, mapValueSize}
|
params := []llvm.Value{m, itfKey, mapValueAlloca, mapValueSize}
|
||||||
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
|
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the resulting value from the hashmap. The value is set to the zero
|
// Load the resulting value from the hashmap. The value is set to the zero
|
||||||
// value if the key doesn't exist in the hashmap.
|
// value if the key doesn't exist in the hashmap.
|
||||||
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
|
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
|
||||||
b.emitLifetimeEnd(mapValuePtr, mapValueAllocaSize)
|
b.emitLifetimeEnd(mapValueAlloca, mapValueAllocaSize)
|
||||||
|
|
||||||
if commaOk {
|
if commaOk {
|
||||||
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{llvmValueType, b.ctx.Int1Type()}, false))
|
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{llvmValueType, b.ctx.Int1Type()}, false))
|
||||||
@@ -124,22 +124,22 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
|
|||||||
// createMapUpdate updates a map key to a given value, by creating an
|
// createMapUpdate updates a map key to a given value, by creating an
|
||||||
// appropriate runtime call.
|
// appropriate runtime call.
|
||||||
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
||||||
valueAlloca, valuePtr, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
|
valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
|
||||||
b.CreateStore(value, valueAlloca)
|
b.CreateStore(value, valueAlloca)
|
||||||
origKeyType := keyType
|
origKeyType := keyType
|
||||||
keyType = keyType.Underlying()
|
keyType = keyType.Underlying()
|
||||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
// key is a string
|
// key is a string
|
||||||
params := []llvm.Value{m, key, valuePtr}
|
params := []llvm.Value{m, key, valueAlloca}
|
||||||
b.createRuntimeCall("hashmapStringSet", params, "")
|
b.createRuntimeCall("hashmapStringSet", params, "")
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
// key can be compared with runtime.memequal
|
// key can be compared with runtime.memequal
|
||||||
keyAlloca, keyPtr, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
b.CreateStore(key, keyAlloca)
|
b.CreateStore(key, keyAlloca)
|
||||||
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
||||||
params := []llvm.Value{m, keyPtr, valuePtr}
|
params := []llvm.Value{m, keyAlloca, valueAlloca}
|
||||||
b.createRuntimeCall("hashmapBinarySet", params, "")
|
b.createRuntimeCall("hashmapBinarySet", params, "")
|
||||||
b.emitLifetimeEnd(keyPtr, keySize)
|
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||||
} else {
|
} else {
|
||||||
// Key is not trivially comparable, so compare it as an interface instead.
|
// Key is not trivially comparable, so compare it as an interface instead.
|
||||||
itfKey := key
|
itfKey := key
|
||||||
@@ -147,10 +147,10 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
|
|||||||
// Not already an interface, so convert it to an interface first.
|
// Not already an interface, so convert it to an interface first.
|
||||||
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
itfKey = b.createMakeInterface(key, origKeyType, pos)
|
||||||
}
|
}
|
||||||
params := []llvm.Value{m, itfKey, valuePtr}
|
params := []llvm.Value{m, itfKey, valueAlloca}
|
||||||
b.createRuntimeCall("hashmapInterfaceSet", params, "")
|
b.createRuntimeCall("hashmapInterfaceSet", params, "")
|
||||||
}
|
}
|
||||||
b.emitLifetimeEnd(valuePtr, valueSize)
|
b.emitLifetimeEnd(valueAlloca, valueSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createMapDelete deletes a key from a map by calling the appropriate runtime
|
// createMapDelete deletes a key from a map by calling the appropriate runtime
|
||||||
@@ -164,12 +164,12 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
|||||||
b.createRuntimeCall("hashmapStringDelete", params, "")
|
b.createRuntimeCall("hashmapStringDelete", params, "")
|
||||||
return nil
|
return nil
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
keyAlloca, keyPtr, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
b.CreateStore(key, keyAlloca)
|
b.CreateStore(key, keyAlloca)
|
||||||
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
|
||||||
params := []llvm.Value{m, keyPtr}
|
params := []llvm.Value{m, keyAlloca}
|
||||||
b.createRuntimeCall("hashmapBinaryDelete", params, "")
|
b.createRuntimeCall("hashmapBinaryDelete", params, "")
|
||||||
b.emitLifetimeEnd(keyPtr, keySize)
|
b.emitLifetimeEnd(keyAlloca, keySize)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
// Key is not trivially comparable, so compare it as an interface
|
// Key is not trivially comparable, so compare it as an interface
|
||||||
@@ -225,9 +225,9 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract the key and value from the map.
|
// Extract the key and value from the map.
|
||||||
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
|
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
|
||||||
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
||||||
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next")
|
||||||
mapKey := b.CreateLoad(llvmStoredKeyType, mapKeyAlloca, "")
|
mapKey := b.CreateLoad(llvmStoredKeyType, mapKeyAlloca, "")
|
||||||
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
|
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
|
||||||
|
|
||||||
@@ -238,8 +238,8 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// End the lifetimes of the allocas, because we're done with them.
|
// End the lifetimes of the allocas, because we're done with them.
|
||||||
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
|
||||||
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
b.emitLifetimeEnd(mapValueAlloca, mapValueSize)
|
||||||
|
|
||||||
// Construct the *ssa.Next return value: {ok, mapKey, mapValue}
|
// Construct the *ssa.Next return value: {ok, mapKey, mapValue}
|
||||||
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
||||||
@@ -333,14 +333,7 @@ func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
|
|||||||
if fieldEndOffset != nextOffset {
|
if fieldEndOffset != nextOffset {
|
||||||
n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
|
n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
|
||||||
llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
|
llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
|
||||||
gepPtr := elemPtr
|
paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), elemPtr, []llvm.Value{llvmStoreSize}, "")
|
||||||
if gepPtr.Type() != b.i8ptrType {
|
|
||||||
gepPtr = b.CreateBitCast(gepPtr, b.i8ptrType, "") // LLVM 14
|
|
||||||
}
|
|
||||||
paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), gepPtr, []llvm.Value{llvmStoreSize}, "")
|
|
||||||
if paddingStart.Type() != b.i8ptrType {
|
|
||||||
paddingStart = b.CreateBitCast(paddingStart, b.i8ptrType, "") // LLVM 14
|
|
||||||
}
|
|
||||||
b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
|
b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-24
@@ -96,7 +96,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
|||||||
// Add an extra parameter as the function context. This context is used in
|
// Add an extra parameter as the function context. This context is used in
|
||||||
// closures and bound methods, but should be optimized away when not used.
|
// closures and bound methods, but should be optimized away when not used.
|
||||||
if !info.exported {
|
if !info.exported {
|
||||||
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", elemSize: 0})
|
paramInfos = append(paramInfos, paramInfo{llvmType: c.dataPtrType, name: "context", elemSize: 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramTypes []llvm.Type
|
var paramTypes []llvm.Type
|
||||||
@@ -145,20 +145,18 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
|||||||
for _, attrName := range []string{"noalias", "nonnull"} {
|
for _, attrName := range []string{"noalias", "nonnull"} {
|
||||||
llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
|
llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
|
||||||
}
|
}
|
||||||
if llvmutil.Major() >= 15 { // allockind etc are not available in LLVM 14
|
// Add attributes to signal to LLVM that this is an allocator function.
|
||||||
// Add attributes to signal to LLVM that this is an allocator
|
// This enables a number of optimizations.
|
||||||
// function. This enables a number of optimizations.
|
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allockind"), allocKindAlloc|allocKindZeroed))
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allockind"), allocKindAlloc|allocKindZeroed))
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("alloc-family", "runtime.alloc"))
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("alloc-family", "runtime.alloc"))
|
// Use a special value to indicate the first parameter:
|
||||||
// Use a special value to indicate the first parameter:
|
// > allocsize has two integer arguments, but because they're both 32 bits, we can
|
||||||
// > allocsize has two integer arguments, but because they're both 32 bits, we can
|
// > pack them into one 64-bit value, at the cost of making said value
|
||||||
// > pack them into one 64-bit value, at the cost of making said value
|
// > nonsensical.
|
||||||
// > nonsensical.
|
// >
|
||||||
// >
|
// > In order to do this, we need to reserve one value of the second (optional)
|
||||||
// > In order to do this, we need to reserve one value of the second (optional)
|
// > allocsize argument to signify "not present."
|
||||||
// > allocsize argument to signify "not present."
|
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allocsize"), 0x0000_0000_ffff_ffff))
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allocsize"), 0x0000_0000_ffff_ffff))
|
|
||||||
}
|
|
||||||
case "runtime.sliceAppend":
|
case "runtime.sliceAppend":
|
||||||
// Appending a slice will only read the to-be-appended slice, it won't
|
// Appending a slice will only read the to-be-appended slice, it won't
|
||||||
// be modified.
|
// be modified.
|
||||||
@@ -445,15 +443,10 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
|
|||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
|
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
|
||||||
if strings.Split(c.Triple, "-")[0] == "x86_64" {
|
if strings.Split(c.Triple, "-")[0] == "x86_64" {
|
||||||
// Required by the ABI.
|
// Required by the ABI.
|
||||||
if llvmutil.Major() < 15 {
|
// The uwtable has two possible values: sync (1) or async (2). We use
|
||||||
// Needed for LLVM 14 support.
|
// sync because we currently don't use async unwind tables.
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 0))
|
// For details, see: https://llvm.org/docs/LangRef.html#function-attributes
|
||||||
} else {
|
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 1))
|
||||||
// The uwtable has two possible values: sync (1) or async (2). We
|
|
||||||
// use sync because we currently don't use async unwind tables.
|
|
||||||
// For details, see: https://llvm.org/docs/LangRef.html#function-attributes
|
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -33,18 +33,17 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
"{r10}",
|
"{r10}",
|
||||||
"{r8}",
|
"{r8}",
|
||||||
"{r9}",
|
"{r9}",
|
||||||
"{r11}",
|
|
||||||
"{r12}",
|
|
||||||
"{r13}",
|
|
||||||
}[i]
|
}[i]
|
||||||
llvmValue := b.getValue(arg, getPos(call))
|
llvmValue := b.getValue(arg, getPos(call))
|
||||||
args = append(args, llvmValue)
|
args = append(args, llvmValue)
|
||||||
argTypes = append(argTypes, llvmValue.Type())
|
argTypes = append(argTypes, llvmValue.Type())
|
||||||
}
|
}
|
||||||
|
// rcx and r11 are clobbered by the syscall, so make sure they are not used
|
||||||
constraints += ",~{rcx},~{r11}"
|
constraints += ",~{rcx},~{r11}"
|
||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||||
return b.CreateCall(fnType, target, args, ""), nil
|
return b.CreateCall(fnType, target, args, ""), nil
|
||||||
|
|
||||||
case b.GOARCH == "386" && b.GOOS == "linux":
|
case b.GOARCH == "386" && b.GOOS == "linux":
|
||||||
// Sources:
|
// Sources:
|
||||||
// syscall(2) man page
|
// syscall(2) man page
|
||||||
@@ -71,6 +70,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
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, true, false, llvm.InlineAsmDialectIntel, false)
|
||||||
return b.CreateCall(fnType, target, args, ""), nil
|
return b.CreateCall(fnType, target, args, ""), nil
|
||||||
|
|
||||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||||
// Implement the EABI system call convention for Linux.
|
// Implement the EABI system call convention for Linux.
|
||||||
// Source: syscall(2) man page.
|
// Source: syscall(2) man page.
|
||||||
@@ -103,6 +103,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
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, true, false, 0, false)
|
||||||
return b.CreateCall(fnType, target, args, ""), nil
|
return b.CreateCall(fnType, target, args, ""), nil
|
||||||
|
|
||||||
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
||||||
// Source: syscall(2) man page.
|
// Source: syscall(2) man page.
|
||||||
args := []llvm.Value{}
|
args := []llvm.Value{}
|
||||||
@@ -135,6 +136,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
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, true, false, 0, false)
|
||||||
return b.CreateCall(fnType, target, args, ""), nil
|
return b.CreateCall(fnType, target, args, ""), nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||||
}
|
}
|
||||||
@@ -183,7 +185,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
llvmType := llvm.FunctionType(b.uintptrType, paramTypes, false)
|
llvmType := llvm.FunctionType(b.uintptrType, paramTypes, false)
|
||||||
fn := b.getValue(call.Args[0], getPos(call))
|
fn := b.getValue(call.Args[0], getPos(call))
|
||||||
fnPtr := b.CreateIntToPtr(fn, llvm.PointerType(llvmType, 0), "")
|
fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
|
||||||
|
|
||||||
// Prepare some functions that will be called later.
|
// Prepare some functions that will be called later.
|
||||||
setLastError := b.mod.NamedFunction("SetLastError")
|
setLastError := b.mod.NamedFunction("SetLastError")
|
||||||
@@ -217,6 +219,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||||
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||||
return retval, nil
|
return retval, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -81,11 +81,11 @@ entry:
|
|||||||
%select.send.value = alloca i32, align 4
|
%select.send.value = alloca i32, align 4
|
||||||
store i32 1, ptr %select.send.value, align 4
|
store i32 1, ptr %select.send.value, align 4
|
||||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
||||||
store ptr %ch1, ptr %select.states.alloca, align 8
|
store ptr %ch1, ptr %select.states.alloca, align 4
|
||||||
%select.states.alloca.repack1 = getelementptr inbounds %runtime.chanSelectState, ptr %select.states.alloca, i32 0, i32 1
|
%select.states.alloca.repack1 = getelementptr inbounds %runtime.chanSelectState, ptr %select.states.alloca, i32 0, i32 1
|
||||||
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
|
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
|
||||||
%0 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1
|
%0 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1
|
||||||
store ptr %ch2, ptr %0, align 8
|
store ptr %ch2, ptr %0, align 4
|
||||||
%.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
|
%.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
|
||||||
store ptr null, ptr %.repack3, align 4
|
store ptr null, ptr %.repack3, align 4
|
||||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
|
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
|
||||||
|
|||||||
+3
-3
@@ -25,7 +25,7 @@ entry:
|
|||||||
%deferPtr = alloca ptr, align 4
|
%deferPtr = alloca ptr, align 4
|
||||||
store ptr null, ptr %deferPtr, align 4
|
store ptr null, ptr %deferPtr, align 4
|
||||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||||
%0 = call ptr @llvm.stacksave()
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
store i32 0, ptr %defer.alloca, align 4
|
store i32 0, ptr %defer.alloca, align 4
|
||||||
%defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
%defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||||
@@ -113,7 +113,7 @@ rundefers.end3: ; preds = %rundefers.loophead6
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
||||||
declare ptr @llvm.stacksave() #3
|
declare ptr @llvm.stacksave.p0() #3
|
||||||
|
|
||||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ entry:
|
|||||||
%deferPtr = alloca ptr, align 4
|
%deferPtr = alloca ptr, align 4
|
||||||
store ptr null, ptr %deferPtr, align 4
|
store ptr null, ptr %deferPtr, align 4
|
||||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||||
%0 = call ptr @llvm.stacksave()
|
%0 = call ptr @llvm.stacksave.p0()
|
||||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||||
store i32 0, ptr %defer.alloca, align 4
|
store i32 0, ptr %defer.alloca, align 4
|
||||||
%defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
%defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||||
|
|||||||
Vendored
+9
-9
@@ -16,9 +16,9 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@main.struct2 = hidden global ptr null, align 4
|
@main.struct2 = hidden global ptr null, align 4
|
||||||
@main.struct3 = hidden global ptr null, align 4
|
@main.struct3 = hidden global ptr null, align 4
|
||||||
@main.struct4 = hidden global ptr null, align 4
|
@main.struct4 = hidden global ptr null, align 4
|
||||||
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||||
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
@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-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-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||||
@@ -104,19 +104,19 @@ entry:
|
|||||||
%stackalloc = alloca i8, align 1
|
%stackalloc = alloca i8, align 1
|
||||||
%makeslice = call dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
%makeslice = call dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice, ptr @main.slice1, align 8
|
store ptr %makeslice, ptr @main.slice1, align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 8
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 4
|
||||||
%makeslice1 = call dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
%makeslice1 = call dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice1, ptr @main.slice2, align 8
|
store ptr %makeslice1, ptr @main.slice2, align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 8
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 4
|
||||||
%makeslice3 = call dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
%makeslice3 = call dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
||||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
||||||
store ptr %makeslice3, ptr @main.slice3, align 8
|
store ptr %makeslice3, ptr @main.slice3, align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
|
||||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 8
|
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -21,7 +21,7 @@ entry:
|
|||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, 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) #9
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
|
|||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, 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) #9
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ entry:
|
|||||||
store i32 5, ptr %0, align 4
|
store i32 5, ptr %0, align 4
|
||||||
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||||
store ptr %n, ptr %1, align 4
|
store ptr %n, ptr %1, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 32768, ptr undef) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||||
%2 = load i32, ptr %n, align 4
|
%2 = load i32, ptr %n, align 4
|
||||||
call void @runtime.printint32(i32 %2, ptr undef) #9
|
call void @runtime.printint32(i32 %2, ptr undef) #9
|
||||||
ret void
|
ret void
|
||||||
@@ -113,7 +113,7 @@ entry:
|
|||||||
store ptr %fn.context, ptr %1, align 4
|
store ptr %fn.context, ptr %1, align 4
|
||||||
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
|
||||||
store ptr %fn.funcptr, ptr %2, align 4
|
store ptr %fn.funcptr, ptr %2, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 32768, ptr undef) #9
|
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ entry:
|
|||||||
store i32 4, ptr %.repack1, align 4
|
store i32 4, ptr %.repack1, align 4
|
||||||
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
||||||
store ptr %itf.typecode, ptr %2, align 4
|
store ptr %itf.typecode, ptr %2, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 32768, 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) #9
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -9,7 +9,7 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 0, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||||
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
@"reflect/types.type.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 } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||||
|
|||||||
Vendored
+2
-2
@@ -122,7 +122,7 @@ entry:
|
|||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.cap = shl i32 %len, 1
|
%makeslice.cap = shl nuw i32 %len, 1
|
||||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||||
@@ -164,7 +164,7 @@ entry:
|
|||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.cap = shl i32 %len, 2
|
%makeslice.cap = shl nuw i32 %len, 2
|
||||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||||
|
|||||||
Vendored
+4
-4
@@ -26,7 +26,7 @@ entry:
|
|||||||
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
|
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
|
||||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||||
store %main.hasPadding %2, ptr %hashmap.key, align 8
|
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||||
@@ -59,7 +59,7 @@ entry:
|
|||||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||||
store i32 5, ptr %hashmap.value, align 4
|
store i32 5, ptr %hashmap.value, align 4
|
||||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||||
store %main.hasPadding %2, ptr %hashmap.key, align 8
|
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||||
@@ -80,7 +80,7 @@ entry:
|
|||||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
|
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||||
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
||||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||||
@@ -108,7 +108,7 @@ entry:
|
|||||||
store i32 5, ptr %hashmap.value, align 4
|
store i32 5, ptr %hashmap.value, align 4
|
||||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
|
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||||
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
||||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||||
|
|||||||
+3
-2
@@ -51,6 +51,7 @@ func TestCorpus(t *testing.T) {
|
|||||||
if *testTarget != "" {
|
if *testTarget != "" {
|
||||||
target = *testTarget
|
target = *testTarget
|
||||||
}
|
}
|
||||||
|
isWASI := strings.HasPrefix(target, "wasi")
|
||||||
|
|
||||||
repos, err := loadRepos(*corpus)
|
repos, err := loadRepos(*corpus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -69,7 +70,7 @@ func TestCorpus(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
if target == "wasi" && repo.SkipWASI {
|
if isWASI && repo.SkipWASI {
|
||||||
t.Skip("skip wasi")
|
t.Skip("skip wasi")
|
||||||
}
|
}
|
||||||
if repo.Slow && testing.Short() {
|
if repo.Slow && testing.Short() {
|
||||||
@@ -135,7 +136,7 @@ func TestCorpus(t *testing.T) {
|
|||||||
t.Run(dir.Pkg, func(t *testing.T) {
|
t.Run(dir.Pkg, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
if target == "wasi" && dir.SkipWASI {
|
if isWASI && dir.SkipWASI {
|
||||||
t.Skip("skip wasi")
|
t.Skip("skip wasi")
|
||||||
}
|
}
|
||||||
if dir.Slow && testing.Short() {
|
if dir.Slow && testing.Short() {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`$(MAKE) <target>' where <target> is one of"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
@echo " dirhtml to make HTML files named index.html in directories"
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
@echo " singlehtml to make a single large HTML file"
|
@echo " singlehtml to make a single large HTML file"
|
||||||
Generated
+60
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1703068421,
|
||||||
|
"narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-23.11",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# A Nix flake file, mainly intended for developing TinyGo.
|
||||||
|
# You can download Nix here, for use on your Linux or macOS system:
|
||||||
|
# https://nixos.org/download.html
|
||||||
|
# After you have installed Nix, you can enter the development environment as
|
||||||
|
# follows:
|
||||||
|
#
|
||||||
|
# nix develop
|
||||||
|
#
|
||||||
|
# This drops you into a bash shell, where you can install TinyGo simply using
|
||||||
|
# the following command:
|
||||||
|
#
|
||||||
|
# go install
|
||||||
|
#
|
||||||
|
# That's all! Assuming you've set up your $PATH correctly, you can now use the
|
||||||
|
# tinygo command as usual:
|
||||||
|
#
|
||||||
|
# tinygo version
|
||||||
|
#
|
||||||
|
# But you'll need a bit more to make TinyGo actually able to compile code:
|
||||||
|
#
|
||||||
|
# make llvm-source # fetch compiler-rt
|
||||||
|
# git submodule update --init # fetch lots of other libraries and SVD files
|
||||||
|
# make gen-device -j4 # build src/device/*/*.go files
|
||||||
|
# make wasi-libc # build support for wasi/wasm
|
||||||
|
#
|
||||||
|
# With this, you should have an environment that can compile anything - except
|
||||||
|
# for the Xtensa architecture (ESP8266/ESP32) because support for that lives in
|
||||||
|
# a separate LLVM fork.
|
||||||
|
#
|
||||||
|
# You can also do many other things from this environment. Building and flashing
|
||||||
|
# should work as you're used to: it's not a VM or container so there are no
|
||||||
|
# access restrictions and you're running in the same host environment - just
|
||||||
|
# with a slightly different set of tools available.
|
||||||
|
{
|
||||||
|
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-23.11";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
{
|
||||||
|
devShells.default = mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
# These dependencies are required for building tinygo (go install).
|
||||||
|
go
|
||||||
|
llvmPackages_17.llvm
|
||||||
|
llvmPackages_17.libclang
|
||||||
|
# Additional dependencies needed at runtime, for building and/or
|
||||||
|
# flashing.
|
||||||
|
llvmPackages_17.lld
|
||||||
|
avrdude
|
||||||
|
binaryen
|
||||||
|
# Additional dependencies needed for on-chip debugging.
|
||||||
|
# These tools are rather big (especially GDB) and not frequently
|
||||||
|
# used, so are commented out. On-chip debugging is still possible if
|
||||||
|
# these tools are available in the host environment.
|
||||||
|
#gdb
|
||||||
|
#openocd
|
||||||
|
];
|
||||||
|
shellHook= ''
|
||||||
|
# Configure CLANG, LLVM_AR, and LLVM_NM for `make wasi-libc`.
|
||||||
|
# Without setting these explicitly, Homebrew versions might be used
|
||||||
|
# or the default `ar` and `nm` tools might be used (which don't
|
||||||
|
# support wasi).
|
||||||
|
export CLANG="clang-17 -resource-dir ${llvmPackages_17.clang.cc.lib}/lib/clang/17"
|
||||||
|
export LLVM_AR=llvm-ar
|
||||||
|
export LLVM_NM=llvm-nm
|
||||||
|
|
||||||
|
# Make `make smoketest` work (the default is `md5`, while Nix only
|
||||||
|
# has `md5sum`).
|
||||||
|
export MD5SUM=md5sum
|
||||||
|
|
||||||
|
# Ugly hack to make the Clang resources directory available.
|
||||||
|
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_17.clang.cc.lib}/lib/clang/17\" -tags=llvm17"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,33 +1,47 @@
|
|||||||
module github.com/tinygo-org/tinygo
|
module github.com/tinygo-org/tinygo
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc
|
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
||||||
github.com/chromedp/chromedp v0.7.6
|
github.com/chromedp/chromedp v0.7.6
|
||||||
|
github.com/client9/misspell v0.3.4
|
||||||
github.com/gofrs/flock v0.8.1
|
github.com/gofrs/flock v0.8.1
|
||||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||||
github.com/mattn/go-colorable v0.1.8
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-tty v0.0.4
|
github.com/mattn/go-tty v0.0.4
|
||||||
|
github.com/mgechev/revive v1.3.7
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||||
go.bug.st/serial v1.6.0
|
go.bug.st/serial v1.6.0
|
||||||
golang.org/x/sys v0.11.0
|
golang.org/x/net v0.26.0
|
||||||
golang.org/x/tools v0.12.0
|
golang.org/x/sys v0.21.0
|
||||||
|
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc
|
tinygo.org/x/go-llvm v0.0.0-20240518103902-697964f2a9dc
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||||
|
github.com/chavacava/garif v0.1.0 // indirect
|
||||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||||
github.com/creack/goselect v0.1.2 // indirect
|
github.com/creack/goselect v0.1.2 // indirect
|
||||||
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
|
github.com/fatih/structtag v1.2.0 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
github.com/gobwas/httphead v0.1.0 // indirect
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
github.com/gobwas/pool v0.2.1 // indirect
|
||||||
github.com/gobwas/ws v1.1.0 // indirect
|
github.com/gobwas/ws v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.12 // 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/text v0.16.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc h1:Yp49g+qqgQRPk/gcRSmAsXgnT16XPJ6Y5JM1poc6gYM=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c h1:4T0Vj1UkGgcpkRrmn7SbokebnlfxJcMZPgWtOYACAAA=
|
||||||
|
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
|
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||||
|
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||||
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
|
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||||
@@ -9,9 +13,17 @@ github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+
|
|||||||
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
|
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
|
||||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||||
|
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
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.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
|
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/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
@@ -31,39 +43,68 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
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.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||||
|
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||||
|
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||||
|
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
|
||||||
|
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
|
||||||
|
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/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
||||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||||
|
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 h1:MMsD8mMfluf/578+3wrTn22pjI/Xkzm+gPW47SYfspY=
|
||||||
|
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc h1:IVX1dqCX3c88P7iEMBtz1xCAM4UIqCMgbqHdSefBaWE=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
tinygo.org/x/go-llvm v0.0.0-20240518103902-697964f2a9dc h1:TCzibFa4oLu+njEP3fnRUmZ+QQeb8BjtOwctgcjzL0k=
|
||||||
|
tinygo.org/x/go-llvm v0.0.0-20240518103902-697964f2a9dc/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||||
|
|||||||
+105
-5
@@ -14,6 +14,8 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keys is a slice of all available environment variable keys.
|
// Keys is a slice of all available environment variable keys.
|
||||||
@@ -33,11 +35,20 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set to true if we're linking statically against LLVM.
|
||||||
|
var hasBuiltinTools = false
|
||||||
|
|
||||||
// TINYGOROOT is the path to the final location for checking tinygo files. If
|
// TINYGOROOT is the path to the final location for checking tinygo files. If
|
||||||
// unset (by a -X ldflag), then sourceDir() will fallback to the original build
|
// unset (by a -X ldflag), then sourceDir() will fallback to the original build
|
||||||
// directory.
|
// directory.
|
||||||
var TINYGOROOT string
|
var TINYGOROOT string
|
||||||
|
|
||||||
|
// If a particular Clang resource dir must always be used and TinyGo can't
|
||||||
|
// figure out the directory using heuristics, this global can be set using a
|
||||||
|
// linker flag.
|
||||||
|
// This is needed for Nix.
|
||||||
|
var clangResourceDir string
|
||||||
|
|
||||||
// Variables read from a `go env` command invocation.
|
// Variables read from a `go env` command invocation.
|
||||||
var goEnvVars struct {
|
var goEnvVars struct {
|
||||||
GOPATH string
|
GOPATH string
|
||||||
@@ -131,11 +142,8 @@ func Get(name string) string {
|
|||||||
}
|
}
|
||||||
return filepath.Join(dir, "tinygo")
|
return filepath.Join(dir, "tinygo")
|
||||||
case "CGO_ENABLED":
|
case "CGO_ENABLED":
|
||||||
val := os.Getenv("CGO_ENABLED")
|
// Always enable CGo. It is required by a number of targets, including
|
||||||
if val == "1" || val == "0" {
|
// macOS and the rp2040.
|
||||||
return val
|
|
||||||
}
|
|
||||||
// Default to enabling CGo.
|
|
||||||
return "1"
|
return "1"
|
||||||
case "TINYGOROOT":
|
case "TINYGOROOT":
|
||||||
return sourceDir()
|
return sourceDir()
|
||||||
@@ -284,3 +292,95 @@ func isSourceDir(root string) bool {
|
|||||||
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClangResourceDir returns the clang resource dir if available. This is the
|
||||||
|
// -resource-dir flag. If it isn't available, an empty string is returned and
|
||||||
|
// -resource-dir should be left unset.
|
||||||
|
// The libclang flag must be set if the resource dir is read for use by
|
||||||
|
// libclang.
|
||||||
|
// In that case, the resource dir is always returned (even when linking
|
||||||
|
// dynamically against LLVM) because libclang always needs this directory.
|
||||||
|
func ClangResourceDir(libclang bool) string {
|
||||||
|
if clangResourceDir != "" {
|
||||||
|
// The resource dir is forced to a particular value at build time.
|
||||||
|
// This is needed on Nix for example, where Clang and libclang don't
|
||||||
|
// know their own resource dir.
|
||||||
|
// Also see:
|
||||||
|
// https://discourse.nixos.org/t/why-is-the-clang-resource-dir-split-in-a-separate-package/34114
|
||||||
|
return clangResourceDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasBuiltinTools && !libclang {
|
||||||
|
// Using external tools, so the resource dir doesn't need to be
|
||||||
|
// specified. Clang knows where to find it.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether we're running from a TinyGo release directory.
|
||||||
|
// This is the case for release binaries on GitHub.
|
||||||
|
root := Get("TINYGOROOT")
|
||||||
|
releaseHeaderDir := filepath.Join(root, "lib", "clang")
|
||||||
|
if _, err := os.Stat(releaseHeaderDir); !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return releaseHeaderDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasBuiltinTools {
|
||||||
|
// We are statically linked to LLVM.
|
||||||
|
// Check whether we're running from the source directory.
|
||||||
|
// This typically happens when TinyGo was built using `make` as part of
|
||||||
|
// development.
|
||||||
|
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
||||||
|
buildResourceDir := filepath.Join(root, "llvm-build", "lib", "clang", llvmMajor)
|
||||||
|
if _, err := os.Stat(buildResourceDir); !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return buildResourceDir
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We use external tools, either when installed using `go install` or
|
||||||
|
// when packaged in a Linux distribution (Linux distros typically prefer
|
||||||
|
// dynamic linking).
|
||||||
|
// Try to detect the system clang resources directory.
|
||||||
|
resourceDir := findSystemClangResources(root)
|
||||||
|
if resourceDir != "" {
|
||||||
|
return resourceDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resource directory not found.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the Clang resource dir on this particular system.
|
||||||
|
// Return the empty string when they aren't found.
|
||||||
|
func findSystemClangResources(TINYGOROOT string) string {
|
||||||
|
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux", "android":
|
||||||
|
// Header files are typically stored in /usr/lib/clang/<version>/include.
|
||||||
|
// Tested on Fedora 39, Debian 12, and Arch Linux.
|
||||||
|
path := filepath.Join("/usr/lib/clang", llvmMajor)
|
||||||
|
_, err := os.Stat(filepath.Join(path, "include", "stdint.h"))
|
||||||
|
if err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
// This assumes a Homebrew installation, like in builder/commands.go.
|
||||||
|
var prefix string
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
prefix = "/usr/local/opt/llvm@" + llvmMajor
|
||||||
|
case "arm64":
|
||||||
|
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor
|
||||||
|
default:
|
||||||
|
return "" // very unlikely for now
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("%s/lib/clang/%s", prefix, llvmMajor)
|
||||||
|
_, err := os.Stat(path + "/include/stdint.h")
|
||||||
|
if err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not find it.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build byollvm
|
||||||
|
|
||||||
|
package goenv
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
hasBuiltinTools = true
|
||||||
|
}
|
||||||
+11
-1
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.30.0"
|
const version = "0.33.0-dev"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// This variable is set at build time using -ldflags parameters.
|
// This variable is set at build time using -ldflags parameters.
|
||||||
@@ -17,6 +17,16 @@ var (
|
|||||||
GitSha1 string
|
GitSha1 string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Return TinyGo version, either in the form 0.30.0 or as a development version
|
||||||
|
// (like 0.30.0-dev-abcd012).
|
||||||
|
func Version() string {
|
||||||
|
v := version
|
||||||
|
if strings.HasSuffix(version, "-dev") && GitSha1 != "" {
|
||||||
|
v += "-" + GitSha1
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
// If the goroot cannot be determined, (0, 0) is returned.
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
func GetGorootVersion() (major, minor int, err error) {
|
func GetGorootVersion() (major, minor int, err error) {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
//go:build tools
|
||||||
|
|
||||||
|
// Install linter versions specified in go.mod
|
||||||
|
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idom
|
||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/client9/misspell"
|
||||||
|
_ "github.com/mgechev/revive"
|
||||||
|
)
|
||||||
+2
-2
@@ -60,10 +60,10 @@ func (r *runner) errorAt(inst instruction, err error) *Error {
|
|||||||
pos := getPosition(inst.llvmInst)
|
pos := getPosition(inst.llvmInst)
|
||||||
return &Error{
|
return &Error{
|
||||||
ImportPath: r.pkgName,
|
ImportPath: r.pkgName,
|
||||||
Inst: inst.String(),
|
Inst: inst.llvmInst.String(),
|
||||||
Pos: pos,
|
Pos: pos,
|
||||||
Err: err,
|
Err: err,
|
||||||
Traceback: []ErrorLine{{pos, inst.String()}},
|
Traceback: []ErrorLine{{pos, inst.llvmInst.String()}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -21,7 +21,7 @@ type runner struct {
|
|||||||
targetData llvm.TargetData
|
targetData llvm.TargetData
|
||||||
builder llvm.Builder
|
builder llvm.Builder
|
||||||
pointerSize uint32 // cached pointer size from the TargetData
|
pointerSize uint32 // cached pointer size from the TargetData
|
||||||
i8ptrType llvm.Type // often used type so created in advance
|
dataPtrType llvm.Type // often used type so created in advance
|
||||||
uintptrType llvm.Type // equivalent to uintptr in Go
|
uintptrType llvm.Type // equivalent to uintptr in Go
|
||||||
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
|
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
|
||||||
debug bool // log debug messages
|
debug bool // log debug messages
|
||||||
@@ -46,9 +46,9 @@ func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
|
|||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
}
|
}
|
||||||
r.pointerSize = uint32(r.targetData.PointerSize())
|
r.pointerSize = uint32(r.targetData.PointerSize())
|
||||||
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
|
r.dataPtrType = llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
r.uintptrType = mod.Context().IntType(r.targetData.PointerSize() * 8)
|
r.uintptrType = mod.Context().IntType(r.targetData.PointerSize() * 8)
|
||||||
r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case)
|
r.maxAlign = r.targetData.PrefTypeAlignment(r.dataPtrType) // assume pointers are maximally aligned (this is not always the case)
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
|
|||||||
mem.revert()
|
mem.revert()
|
||||||
// Create a call to the package initializer (which was
|
// Create a call to the package initializer (which was
|
||||||
// previously deleted).
|
// previously deleted).
|
||||||
i8undef := llvm.Undef(r.i8ptrType)
|
i8undef := llvm.Undef(r.dataPtrType)
|
||||||
r.builder.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{i8undef}, "")
|
r.builder.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{i8undef}, "")
|
||||||
// Make sure that any globals touched by the package
|
// Make sure that any globals touched by the package
|
||||||
// initializer, won't be accessed by later package initializers.
|
// initializer, won't be accessed by later package initializers.
|
||||||
@@ -174,8 +174,7 @@ func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
|
|||||||
newGlobal.SetLinkage(obj.llvmGlobal.Linkage())
|
newGlobal.SetLinkage(obj.llvmGlobal.Linkage())
|
||||||
newGlobal.SetAlignment(obj.llvmGlobal.Alignment())
|
newGlobal.SetAlignment(obj.llvmGlobal.Alignment())
|
||||||
// TODO: copy debug info, unnamed_addr, ...
|
// TODO: copy debug info, unnamed_addr, ...
|
||||||
bitcast := llvm.ConstBitCast(newGlobal, obj.llvmGlobal.Type())
|
obj.llvmGlobal.ReplaceAllUsesWith(newGlobal)
|
||||||
obj.llvmGlobal.ReplaceAllUsesWith(bitcast)
|
|
||||||
name := obj.llvmGlobal.Name()
|
name := obj.llvmGlobal.Name()
|
||||||
obj.llvmGlobal.EraseFromParentAsGlobal()
|
obj.llvmGlobal.EraseFromParentAsGlobal()
|
||||||
newGlobal.SetName(name)
|
newGlobal.SetName(name)
|
||||||
|
|||||||
@@ -77,12 +77,9 @@ func runTest(t *testing.T, pathPrefix string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run some cleanup passes to get easy-to-read outputs.
|
// Run some cleanup passes to get easy-to-read outputs.
|
||||||
pm := llvm.NewPassManager()
|
to := llvm.NewPassBuilderOptions()
|
||||||
defer pm.Dispose()
|
defer to.Dispose()
|
||||||
pm.AddGlobalOptimizerPass()
|
mod.RunPasses("globalopt,dse,adce", llvm.TargetMachine{}, to)
|
||||||
pm.AddDeadStoreEliminationPass()
|
|
||||||
pm.AddAggressiveDCEPass()
|
|
||||||
pm.Run(mod)
|
|
||||||
|
|
||||||
// Read the expected output IR.
|
// Read the expected output IR.
|
||||||
out, err := os.ReadFile(pathPrefix + ".out.ll")
|
out, err := os.ReadFile(pathPrefix + ".out.ll")
|
||||||
|
|||||||
+39
-23
@@ -239,7 +239,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// already be emitted in initAll.
|
// already be emitted in initAll.
|
||||||
continue
|
continue
|
||||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "runtime.hashmapInterfaceHash" ||
|
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "runtime.hashmapInterfaceHash" ||
|
||||||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
|
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current" ||
|
||||||
|
callFn.name == "time.startTimer" || callFn.name == "time.stopTimer" || callFn.name == "time.resetTimer":
|
||||||
// These functions should be run at runtime. Specifically:
|
// These functions should be run at runtime. Specifically:
|
||||||
// * Print and panic functions are best emitted directly without
|
// * Print and panic functions are best emitted directly without
|
||||||
// interpreting them, otherwise we get a ton of putchar (etc.)
|
// interpreting them, otherwise we get a ton of putchar (etc.)
|
||||||
@@ -252,6 +253,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// at runtime.
|
// at runtime.
|
||||||
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
||||||
// which is modified elsewhere.
|
// which is modified elsewhere.
|
||||||
|
// * Timer functions access runtime internal state which may
|
||||||
|
// not be initialized.
|
||||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, err
|
return nil, mem, err
|
||||||
@@ -424,7 +427,22 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
// typecodePtr always point to the numMethod field in the type
|
||||||
|
// description struct. The methodSet, when present, comes right
|
||||||
|
// before the numMethod field (the compiler doesn't generate
|
||||||
|
// method sets for concrete types without methods).
|
||||||
|
// Considering that the compiler doesn't emit interface type
|
||||||
|
// asserts for interfaces with no methods (as the always succeed)
|
||||||
|
// then if the offset is zero, this assert must always fail.
|
||||||
|
if typecodePtr.offset() == 0 {
|
||||||
|
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
|
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
@@ -470,7 +488,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
|
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
@@ -543,7 +565,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// how this function got called.
|
// how this function got called.
|
||||||
callErr.Traceback = append(callErr.Traceback, ErrorLine{
|
callErr.Traceback = append(callErr.Traceback, ErrorLine{
|
||||||
Pos: getPosition(inst.llvmInst),
|
Pos: getPosition(inst.llvmInst),
|
||||||
Inst: inst.String(),
|
Inst: inst.llvmInst.String(),
|
||||||
})
|
})
|
||||||
return nil, mem, callErr
|
return nil, mem, callErr
|
||||||
}
|
}
|
||||||
@@ -633,11 +655,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
case llvm.GetElementPtr:
|
case llvm.GetElementPtr:
|
||||||
// GetElementPtr does pointer arithmetic, changing the offset of the
|
// GetElementPtr does pointer arithmetic, changing the offset of the
|
||||||
// pointer into the underlying object.
|
// pointer into the underlying object.
|
||||||
var offset uint64
|
var offset int64
|
||||||
for i := 1; i < len(operands); i += 2 {
|
for i := 1; i < len(operands); i += 2 {
|
||||||
index := operands[i].Uint()
|
index := operands[i].Int()
|
||||||
elementSize := operands[i+1].Uint()
|
elementSize := operands[i+1].Int()
|
||||||
if int64(elementSize) < 0 {
|
if elementSize < 0 {
|
||||||
// This is a struct field.
|
// This is a struct field.
|
||||||
offset += index
|
offset += index
|
||||||
} else {
|
} else {
|
||||||
@@ -651,11 +673,14 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||||
ptrValue := operands[0].Uint() + offset
|
ptrValue := operands[0].Uint() + uint64(offset)
|
||||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ptr = ptr.addOffset(int64(offset))
|
ptr, err = ptr.addOffset(int64(offset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
locals[inst.localIndex] = ptr
|
locals[inst.localIndex] = ptr
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, indent+"gep:", operands, "->", ptr)
|
fmt.Fprintln(os.Stderr, indent+"gep:", operands, "->", ptr)
|
||||||
@@ -753,7 +778,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if inst.opcode == llvm.Add {
|
if inst.opcode == llvm.Add {
|
||||||
// This likely means this is part of a
|
// This likely means this is part of a
|
||||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||||
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
|
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
locals[inst.localIndex] = lhsPtr
|
locals[inst.localIndex] = lhsPtr
|
||||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
||||||
// Special workaround for strings.noescape, see
|
// Special workaround for strings.noescape, see
|
||||||
@@ -1046,15 +1074,3 @@ func intPredicateString(predicate llvm.IntPredicate) string {
|
|||||||
return "cmp?"
|
return "cmp?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip some pointer casts. This is probably unnecessary once support for
|
|
||||||
// LLVM 14 (non-opaque pointers) is dropped.
|
|
||||||
func stripPointerCasts(value llvm.Value) llvm.Value {
|
|
||||||
if !value.IsAConstantExpr().IsNil() {
|
|
||||||
switch value.Opcode() {
|
|
||||||
case llvm.GetElementPtr, llvm.BitCast:
|
|
||||||
return stripPointerCasts(value.Operand(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|||||||
+7
-18
@@ -517,12 +517,12 @@ func (v pointerValue) offset() uint32 {
|
|||||||
// addOffset essentially does a GEP operation (pointer arithmetic): it adds the
|
// addOffset essentially does a GEP operation (pointer arithmetic): it adds the
|
||||||
// offset to the pointer. It also checks that the offset doesn't overflow the
|
// offset to the pointer. It also checks that the offset doesn't overflow the
|
||||||
// maximum offset size (which is 4GB).
|
// maximum offset size (which is 4GB).
|
||||||
func (v pointerValue) addOffset(offset int64) pointerValue {
|
func (v pointerValue) addOffset(offset int64) (pointerValue, error) {
|
||||||
result := pointerValue{v.pointer + uint64(offset)}
|
result := pointerValue{v.pointer + uint64(offset)}
|
||||||
if checks && v.index() != result.index() {
|
if checks && v.index() != result.index() {
|
||||||
panic("interp: offset out of range")
|
return result, fmt.Errorf("interp: offset %d out of range for object %v", offset, v)
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v pointerValue) len(r *runner) uint32 {
|
func (v pointerValue) len(r *runner) uint32 {
|
||||||
@@ -658,20 +658,11 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
|
|||||||
if v.offset() != 0 {
|
if v.offset() != 0 {
|
||||||
// If there is an offset, make sure to use a GEP to index into the
|
// If there is an offset, make sure to use a GEP to index into the
|
||||||
// pointer.
|
// pointer.
|
||||||
// Cast to an i8* first (if needed) for easy indexing.
|
|
||||||
if llvmValue.Type() != mem.r.i8ptrType {
|
|
||||||
llvmValue = llvm.ConstBitCast(llvmValue, mem.r.i8ptrType)
|
|
||||||
}
|
|
||||||
llvmValue = llvm.ConstInBoundsGEP(mem.r.mod.Context().Int8Type(), llvmValue, []llvm.Value{
|
llvmValue = llvm.ConstInBoundsGEP(mem.r.mod.Context().Int8Type(), llvmValue, []llvm.Value{
|
||||||
llvm.ConstInt(mem.r.mod.Context().Int32Type(), uint64(v.offset()), false),
|
llvm.ConstInt(mem.r.mod.Context().Int32Type(), uint64(v.offset()), false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a particular LLVM pointer type is requested, cast to it.
|
|
||||||
if !llvmType.IsNil() && llvmType != llvmValue.Type() {
|
|
||||||
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return llvmValue, nil
|
return llvmValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +863,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if checks && mem.r.targetData.TypeAllocSize(llvmType) != mem.r.targetData.TypeAllocSize(mem.r.i8ptrType) {
|
if checks && mem.r.targetData.TypeAllocSize(llvmType) != mem.r.targetData.TypeAllocSize(mem.r.dataPtrType) {
|
||||||
// Probably trying to serialize a pointer to a byte array,
|
// Probably trying to serialize a pointer to a byte array,
|
||||||
// perhaps as a result of rawLLVMValue() in a previous interp
|
// perhaps as a result of rawLLVMValue() in a previous interp
|
||||||
// run.
|
// run.
|
||||||
@@ -954,8 +945,6 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
|||||||
// Because go-llvm doesn't have addrspacecast at the moment,
|
// Because go-llvm doesn't have addrspacecast at the moment,
|
||||||
// do it indirectly with a ptrtoint/inttoptr pair.
|
// do it indirectly with a ptrtoint/inttoptr pair.
|
||||||
llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
|
llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
|
||||||
} else {
|
|
||||||
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return llvmValue, nil
|
return llvmValue, nil
|
||||||
@@ -1256,7 +1245,7 @@ func (r *runner) getValue(llvmValue llvm.Value) value {
|
|||||||
// For details on this format, see src/runtime/gc_precise.go.
|
// For details on this format, see src/runtime/gc_precise.go.
|
||||||
func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
|
func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
|
||||||
pointerSize := layoutValue.len(r)
|
pointerSize := layoutValue.len(r)
|
||||||
if checks && uint64(pointerSize) != r.targetData.TypeAllocSize(r.i8ptrType) {
|
if checks && uint64(pointerSize) != r.targetData.TypeAllocSize(r.dataPtrType) {
|
||||||
panic("inconsistent pointer size")
|
panic("inconsistent pointer size")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,12 +1320,12 @@ func (r *runner) getLLVMTypeFromLayout(layoutValue value) llvm.Type {
|
|||||||
|
|
||||||
// Create the LLVM type.
|
// Create the LLVM type.
|
||||||
pointerSize := layoutValue.len(r)
|
pointerSize := layoutValue.len(r)
|
||||||
pointerAlignment := r.targetData.PrefTypeAlignment(r.i8ptrType)
|
pointerAlignment := r.targetData.PrefTypeAlignment(r.dataPtrType)
|
||||||
var fields []llvm.Type
|
var fields []llvm.Type
|
||||||
for i := 0; i < int(objectSizeWords); {
|
for i := 0; i < int(objectSizeWords); {
|
||||||
if bitmap.Bit(i) != 0 {
|
if bitmap.Bit(i) != 0 {
|
||||||
// Pointer field.
|
// Pointer field.
|
||||||
fields = append(fields, r.i8ptrType)
|
fields = append(fields, r.dataPtrType)
|
||||||
i += int(pointerSize / uint32(pointerAlignment))
|
i += int(pointerSize / uint32(pointerAlignment))
|
||||||
} else {
|
} else {
|
||||||
// Byte/word field.
|
// Byte/word field.
|
||||||
|
|||||||
Vendored
+7
@@ -10,6 +10,8 @@ target triple = "x86_64--linux"
|
|||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = global i16 0
|
@main.exposedValue2 = global i16 0
|
||||||
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
||||||
|
@main.gepArray = global [8 x i8] zeroinitializer
|
||||||
|
@main.negativeGEP = global ptr null
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
@@ -88,6 +90,11 @@ entry:
|
|||||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
||||||
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
||||||
|
|
||||||
|
; negative GEP instruction
|
||||||
|
%ngep1 = getelementptr [8 x i8], ptr @main.negativeGEP, i32 0, i32 5
|
||||||
|
%ngep2 = getelementptr [8 x i8], ptr %ngep1, i32 0, i32 -3
|
||||||
|
store ptr %ngep2, ptr @main.negativeGEP
|
||||||
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
@@ -9,6 +9,8 @@ target triple = "x86_64--linux"
|
|||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||||
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||||
|
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
||||||
|
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule lib/binaryen updated: 96f7acf09a...11dba9b1c2
+1
-1
Submodule lib/cmsis-svd updated: df75ff974c...40327a4d2d
+1
-1
Submodule lib/wasi-libc updated: 30094b6ed0...1dfe5c302d
+7
-4
@@ -18,7 +18,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@@ -157,7 +156,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
|||||||
|
|
||||||
// Add files from TinyGo.
|
// Add files from TinyGo.
|
||||||
tinygoDir := filepath.Join(tinygoSrc, dir)
|
tinygoDir := filepath.Join(tinygoSrc, dir)
|
||||||
tinygoEntries, err := ioutil.ReadDir(tinygoDir)
|
tinygoEntries, err := os.ReadDir(tinygoDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -177,7 +176,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
|||||||
// Add all directories from $GOROOT that are not part of the TinyGo
|
// Add all directories from $GOROOT that are not part of the TinyGo
|
||||||
// overrides.
|
// overrides.
|
||||||
goDir := filepath.Join(goSrc, dir)
|
goDir := filepath.Join(goSrc, dir)
|
||||||
goEntries, err := ioutil.ReadDir(goDir)
|
goEntries, err := os.ReadDir(goDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -215,7 +214,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
|||||||
return merges, nil
|
return merges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// needsSyscallPackage returns whether the syscall package should be overriden
|
// needsSyscallPackage returns whether the syscall package should be overridden
|
||||||
// with the TinyGo version. This is the case on some targets.
|
// with the TinyGo version. This is the case on some targets.
|
||||||
func needsSyscallPackage(buildTags []string) bool {
|
func needsSyscallPackage(buildTags []string) bool {
|
||||||
for _, tag := range buildTags {
|
for _, tag := range buildTags {
|
||||||
@@ -233,16 +232,20 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
|||||||
"": true,
|
"": true,
|
||||||
"crypto/": true,
|
"crypto/": true,
|
||||||
"crypto/rand/": false,
|
"crypto/rand/": false,
|
||||||
|
"crypto/tls/": false,
|
||||||
"device/": false,
|
"device/": false,
|
||||||
"examples/": false,
|
"examples/": false,
|
||||||
"internal/": true,
|
"internal/": true,
|
||||||
|
"internal/binary/": false,
|
||||||
"internal/bytealg/": false,
|
"internal/bytealg/": false,
|
||||||
"internal/fuzz/": false,
|
"internal/fuzz/": false,
|
||||||
"internal/reflectlite/": false,
|
"internal/reflectlite/": false,
|
||||||
"internal/task/": false,
|
"internal/task/": false,
|
||||||
"machine/": false,
|
"machine/": false,
|
||||||
"net/": true,
|
"net/": true,
|
||||||
|
"net/http/": false,
|
||||||
"os/": true,
|
"os/": true,
|
||||||
|
"os/user/": false,
|
||||||
"reflect/": false,
|
"reflect/": false,
|
||||||
"runtime/": false,
|
"runtime/": false,
|
||||||
"sync/": true,
|
"sync/": true,
|
||||||
|
|||||||
+1
-5
@@ -22,12 +22,8 @@ func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, erro
|
|||||||
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
||||||
}
|
}
|
||||||
args = append(args, pkgs...)
|
args = append(args, pkgs...)
|
||||||
cgoEnabled := "0"
|
|
||||||
if config.CgoEnabled() {
|
|
||||||
cgoEnabled = "1"
|
|
||||||
}
|
|
||||||
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "go"), args...)
|
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "go"), args...)
|
||||||
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED="+cgoEnabled)
|
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED=1")
|
||||||
if config.Options.Directory != "" {
|
if config.Options.Directory != "" {
|
||||||
cmd.Dir = config.Options.Directory
|
cmd.Dir = config.Options.Directory
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-17
@@ -27,13 +27,14 @@ import (
|
|||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var initFileVersions = func(info *types.Info) {}
|
||||||
|
|
||||||
// Program holds all packages and some metadata about the program as a whole.
|
// Program holds all packages and some metadata about the program as a whole.
|
||||||
type Program struct {
|
type Program struct {
|
||||||
config *compileopts.Config
|
config *compileopts.Config
|
||||||
clangHeaders string
|
typeChecker types.Config
|
||||||
typeChecker types.Config
|
goroot string // synthetic GOROOT
|
||||||
goroot string // synthetic GOROOT
|
workingDir string
|
||||||
workingDir string
|
|
||||||
|
|
||||||
Packages map[string]*Package
|
Packages map[string]*Package
|
||||||
sorted []*Package
|
sorted []*Package
|
||||||
@@ -103,7 +104,7 @@ type EmbedFile struct {
|
|||||||
// Load loads the given package with all dependencies (including the runtime
|
// Load loads the given package with all dependencies (including the runtime
|
||||||
// package). Call .Parse() afterwards to parse all Go files (including CGo
|
// package). Call .Parse() afterwards to parse all Go files (including CGo
|
||||||
// processing, if necessary).
|
// processing, if necessary).
|
||||||
func Load(config *compileopts.Config, inputPkg string, clangHeaders string, typeChecker types.Config) (*Program, error) {
|
func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config) (*Program, error) {
|
||||||
goroot, err := GetCachedGoroot(config)
|
goroot, err := GetCachedGoroot(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -118,13 +119,12 @@ func Load(config *compileopts.Config, inputPkg string, clangHeaders string, type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
p := &Program{
|
p := &Program{
|
||||||
config: config,
|
config: config,
|
||||||
clangHeaders: clangHeaders,
|
typeChecker: typeChecker,
|
||||||
typeChecker: typeChecker,
|
goroot: goroot,
|
||||||
goroot: goroot,
|
workingDir: wd,
|
||||||
workingDir: wd,
|
Packages: make(map[string]*Package),
|
||||||
Packages: make(map[string]*Package),
|
fset: token.NewFileSet(),
|
||||||
fset: token.NewFileSet(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List the dependencies of this package, in raw JSON format.
|
// List the dependencies of this package, in raw JSON format.
|
||||||
@@ -380,6 +380,24 @@ func (p *Package) Check() error {
|
|||||||
typeErrors = append(typeErrors, err)
|
typeErrors = append(typeErrors, err)
|
||||||
}
|
}
|
||||||
checker.Importer = p
|
checker.Importer = p
|
||||||
|
if p.Module.GoVersion != "" {
|
||||||
|
// Setting the Go version for a module makes sure the type checker
|
||||||
|
// errors out on language features not supported in that particular
|
||||||
|
// version.
|
||||||
|
checker.GoVersion = "go" + p.Module.GoVersion
|
||||||
|
} else {
|
||||||
|
// Version is not known, so use the currently installed Go version.
|
||||||
|
// This is needed for `tinygo run` for example.
|
||||||
|
// Normally we'd use goenv.GorootVersionString(), but for compatibility
|
||||||
|
// with Go 1.20 and below we need a version in the form of "go1.12" (no
|
||||||
|
// patch version).
|
||||||
|
major, minor, err := goenv.GetGorootVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor)
|
||||||
|
}
|
||||||
|
initFileVersions(&p.info)
|
||||||
|
|
||||||
// Do typechecking of the package.
|
// Do typechecking of the package.
|
||||||
packageName := p.ImportPath
|
packageName := p.ImportPath
|
||||||
@@ -412,7 +430,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
|||||||
var files []*ast.File
|
var files []*ast.File
|
||||||
var fileErrs []error
|
var fileErrs []error
|
||||||
|
|
||||||
// Parse all files (incuding CgoFiles).
|
// Parse all files (including CgoFiles).
|
||||||
parseFile := func(file string) {
|
parseFile := func(file string) {
|
||||||
if !filepath.IsAbs(file) {
|
if !filepath.IsAbs(file) {
|
||||||
file = filepath.Join(p.Dir, file)
|
file = filepath.Join(p.Dir, file)
|
||||||
@@ -438,9 +456,9 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
|||||||
// to call cgo.Process in that case as it will only cause issues.
|
// to call cgo.Process in that case as it will only cause issues.
|
||||||
if len(p.CgoFiles) != 0 && len(files) != 0 {
|
if len(p.CgoFiles) != 0 && len(files) != 0 {
|
||||||
var initialCFlags []string
|
var initialCFlags []string
|
||||||
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
|
initialCFlags = append(initialCFlags, p.program.config.CFlags(true)...)
|
||||||
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
||||||
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.clangHeaders)
|
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags)
|
||||||
p.CFlags = append(initialCFlags, cflags...)
|
p.CFlags = append(initialCFlags, cflags...)
|
||||||
p.CGoHeaders = headerCode
|
p.CGoHeaders = headerCode
|
||||||
for path, hash := range accessedFiles {
|
for path, hash := range accessedFiles {
|
||||||
@@ -449,7 +467,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
|||||||
if errs != nil {
|
if errs != nil {
|
||||||
fileErrs = append(fileErrs, errs...)
|
fileErrs = append(fileErrs, errs...)
|
||||||
}
|
}
|
||||||
files = append(files, generated)
|
files = append(files, generated...)
|
||||||
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//go:build go1.22
|
||||||
|
|
||||||
|
// types.Info.FileVersions was added in Go 1.22, so we can only initialize it
|
||||||
|
// when built with Go 1.22.
|
||||||
|
|
||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initFileVersions = func(info *types.Info) {
|
||||||
|
info.FileVersions = make(map[*ast.File]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/types"
|
"go/types"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -286,7 +285,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
|||||||
// Tests are always run in the package directory.
|
// Tests are always run in the package directory.
|
||||||
cmd.Dir = result.MainDir
|
cmd.Dir = result.MainDir
|
||||||
|
|
||||||
// wasmtime is the default emulator used for `-target=wasi`. wasmtime
|
// wasmtime is the default emulator used for `-target=wasip1`. wasmtime
|
||||||
// is a WebAssembly runtime CLI with WASI enabled by default. However,
|
// is a WebAssembly runtime CLI with WASI enabled by default. However,
|
||||||
// only stdio are allowed by default. For example, while STDOUT routes
|
// only stdio are allowed by default. For example, while STDOUT routes
|
||||||
// to the host, other files don't. It also does not inherit environment
|
// to the host, other files don't. It also does not inherit environment
|
||||||
@@ -533,7 +532,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
|||||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||||
}
|
}
|
||||||
if options.Monitor {
|
if options.Monitor {
|
||||||
return Monitor(result.Executable, "", options)
|
return Monitor(result.Executable, "", config)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -798,7 +797,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||||||
needsEnvInVars = true
|
needsEnvInVars = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var args, env []string
|
var args, emuArgs, env []string
|
||||||
var extraCmdEnv []string
|
var extraCmdEnv []string
|
||||||
if needsEnvInVars {
|
if needsEnvInVars {
|
||||||
runtimeGlobals := make(map[string]string)
|
runtimeGlobals := make(map[string]string)
|
||||||
@@ -821,13 +820,14 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||||||
} else if config.EmulatorName() == "wasmtime" {
|
} else if config.EmulatorName() == "wasmtime" {
|
||||||
// Wasmtime needs some special flags to pass environment variables
|
// Wasmtime needs some special flags to pass environment variables
|
||||||
// and allow reading from the current directory.
|
// and allow reading from the current directory.
|
||||||
args = append(args, "--dir=.")
|
emuArgs = append(emuArgs, "--dir=.")
|
||||||
for _, v := range environmentVars {
|
for _, v := range environmentVars {
|
||||||
args = append(args, "--env", v)
|
emuArgs = append(emuArgs, "--env", v)
|
||||||
}
|
}
|
||||||
if len(cmdArgs) != 0 {
|
if len(cmdArgs) != 0 {
|
||||||
// mark end of wasmtime arguments and start of program ones: --
|
// Use of '--' argument no longer necessary as of Wasmtime v14:
|
||||||
args = append(args, "--")
|
// https://github.com/bytecodealliance/wasmtime/pull/6946
|
||||||
|
// args = append(args, "--")
|
||||||
args = append(args, cmdArgs...)
|
args = append(args, cmdArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,7 +877,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
name = emulator[0]
|
name = emulator[0]
|
||||||
emuArgs := append([]string(nil), emulator[1:]...)
|
emuArgs = append(emuArgs, emulator[1:]...)
|
||||||
args = append(emuArgs, args...)
|
args = append(emuArgs, args...)
|
||||||
}
|
}
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
@@ -1033,9 +1033,10 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
|
|||||||
if fstype != "vfat" {
|
if fstype != "vfat" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
fspath := strings.ReplaceAll(fields[1], "\\040", " ")
|
||||||
points = append(points, mountPoint{
|
points = append(points, mountPoint{
|
||||||
name: filepath.Base(fields[1]),
|
name: filepath.Base(fspath),
|
||||||
path: fields[1],
|
path: fspath,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return points, nil
|
return points, nil
|
||||||
@@ -1212,15 +1213,10 @@ func getBMPPorts() (gdbPort, uartPort string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func usage(command string) {
|
func usage(command string) {
|
||||||
version := goenv.Version
|
|
||||||
if strings.HasSuffix(version, "-dev") && goenv.GitSha1 != "" {
|
|
||||||
version += "-" + goenv.GitSha1
|
|
||||||
}
|
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
default:
|
default:
|
||||||
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
|
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
|
||||||
fmt.Fprintln(os.Stderr, "version:", version)
|
fmt.Fprintln(os.Stderr, "version:", goenv.Version())
|
||||||
fmt.Fprintf(os.Stderr, "usage: %s <command> [arguments]\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "usage: %s <command> [arguments]\n", os.Args[0])
|
||||||
fmt.Fprintln(os.Stderr, "\ncommands:")
|
fmt.Fprintln(os.Stderr, "\ncommands:")
|
||||||
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
|
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
|
||||||
@@ -1230,6 +1226,7 @@ func usage(command string) {
|
|||||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||||
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
||||||
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
||||||
|
fmt.Fprintln(os.Stderr, " ports: list available serial ports")
|
||||||
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
||||||
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
||||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||||
@@ -1415,7 +1412,7 @@ func main() {
|
|||||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
|
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
|
||||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
||||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)")
|
||||||
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
||||||
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
||||||
var tags buildutil.TagsFlag
|
var tags buildutil.TagsFlag
|
||||||
@@ -1737,35 +1734,33 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
case "monitor":
|
case "monitor":
|
||||||
err := Monitor("", *port, options)
|
config, err := builder.NewConfig(options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
|
err = Monitor("", *port, config)
|
||||||
|
handleCompilerError(err)
|
||||||
|
case "ports":
|
||||||
|
serialPortInfo, err := ListSerialPorts()
|
||||||
|
handleCompilerError(err)
|
||||||
|
if len(serialPortInfo) == 0 {
|
||||||
|
fmt.Println("No serial ports found.")
|
||||||
|
}
|
||||||
|
fmt.Printf("%-20s %-9s %s\n", "Port", "ID", "Boards")
|
||||||
|
for _, s := range serialPortInfo {
|
||||||
|
fmt.Printf("%-20s %4s:%4s %s\n", s.Name, s.VID, s.PID, s.Target)
|
||||||
|
}
|
||||||
case "targets":
|
case "targets":
|
||||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
specs, err := compileopts.GetTargetSpecs()
|
||||||
entries, err := ioutil.ReadDir(dir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "could not list targets:", err)
|
fmt.Fprintln(os.Stderr, "could not list targets:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, entry := range entries {
|
names := []string{}
|
||||||
if !entry.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
|
for key := range specs {
|
||||||
// Only inspect JSON files.
|
names = append(names, key)
|
||||||
continue
|
}
|
||||||
}
|
sort.Strings(names)
|
||||||
path := filepath.Join(dir, entry.Name())
|
for _, name := range names {
|
||||||
spec, err := compileopts.LoadTarget(&compileopts.Options{Target: path})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "could not list target:", err)
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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).
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := entry.Name()
|
|
||||||
name = name[:len(name)-5]
|
|
||||||
fmt.Println(name)
|
fmt.Println(name)
|
||||||
}
|
}
|
||||||
case "info":
|
case "info":
|
||||||
@@ -1874,11 +1869,7 @@ func main() {
|
|||||||
if s, err := goenv.GorootVersionString(); err == nil {
|
if s, err := goenv.GorootVersionString(); err == nil {
|
||||||
goversion = s
|
goversion = s
|
||||||
}
|
}
|
||||||
version := goenv.Version
|
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", goenv.Version(), runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
|
||||||
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
|
|
||||||
version += "-" + goenv.GitSha1
|
|
||||||
}
|
|
||||||
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
|
|
||||||
case "env":
|
case "env":
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
// Show all environment variables.
|
// Show all environment variables.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user