mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 11:07:46 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 277b3f71e3 |
+25
-32
@@ -22,16 +22,15 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-14-v3
|
- llvm-source-13-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-14-v3
|
key: llvm-source-13-v1
|
||||||
paths:
|
paths:
|
||||||
- llvm-project/clang/lib/Headers
|
- llvm-project/clang/lib/Headers
|
||||||
- llvm-project/clang/include
|
- llvm-project/clang/include
|
||||||
- llvm-project/compiler-rt
|
|
||||||
- llvm-project/lld/include
|
- llvm-project/lld/include
|
||||||
- llvm-project/llvm/include
|
- llvm-project/llvm/include
|
||||||
hack-ninja-jobs:
|
hack-ninja-jobs:
|
||||||
@@ -45,32 +44,29 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- binaryen-linux-v2
|
- binaryen-linux-v1
|
||||||
- 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-v1
|
||||||
paths:
|
paths:
|
||||||
- build/wasm-opt
|
- build/wasm-opt
|
||||||
test-linux:
|
test-linux:
|
||||||
parameters:
|
parameters:
|
||||||
llvm:
|
llvm:
|
||||||
type: string
|
type: string
|
||||||
fmt-check:
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- submodules
|
- submodules
|
||||||
- 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/buster/ llvm-toolchain-buster-<<parameters.llvm>> main' | sudo tee /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 | sudo apt-key add -
|
||||||
apt-get update
|
sudo apt-get update
|
||||||
apt-get install --no-install-recommends -y \
|
sudo apt-get install --no-install-recommends \
|
||||||
llvm-<<parameters.llvm>>-dev \
|
llvm-<<parameters.llvm>>-dev \
|
||||||
clang-<<parameters.llvm>> \
|
clang-<<parameters.llvm>> \
|
||||||
libclang-<<parameters.llvm>>-dev \
|
libclang-<<parameters.llvm>>-dev \
|
||||||
@@ -83,46 +79,43 @@ 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-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||||
- go-cache-v3-{{ checksum "go.mod" }}
|
- go-cache-v2-{{ 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-v3
|
||||||
- run: make wasi-libc
|
- run: make wasi-libc
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: wasi-libc-sysroot-systemclang-v6
|
key: wasi-libc-sysroot-systemclang-v3
|
||||||
paths:
|
paths:
|
||||||
- lib/wasi-libc/sysroot
|
- lib/wasi-libc/sysroot
|
||||||
- when:
|
|
||||||
condition: <<parameters.fmt-check>>
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
# Do this before gen-device so that it doesn't check the
|
|
||||||
# formatting of generated files.
|
|
||||||
name: Check Go code formatting
|
|
||||||
command: make fmt-check
|
|
||||||
- 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-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/go-build
|
- ~/.cache/go-build
|
||||||
- /go/pkg/mod
|
- /go/pkg/mod
|
||||||
|
- run: make fmt-check
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-llvm14-go118:
|
test-llvm11-go115:
|
||||||
docker:
|
docker:
|
||||||
- image: golang:1.18-buster
|
- image: circleci/golang:1.15-buster
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "14"
|
llvm: "11"
|
||||||
resource_class: large
|
test-llvm12-go116:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.16-buster
|
||||||
|
steps:
|
||||||
|
- test-linux:
|
||||||
|
llvm: "12"
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
test-all:
|
test-all:
|
||||||
jobs:
|
jobs:
|
||||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
- test-llvm11-go115
|
||||||
# least the smoke tests still pass.
|
- test-llvm12-go116
|
||||||
- test-llvm14-go118
|
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- release
|
- release
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-macos:
|
build-macos:
|
||||||
name: build-macos
|
name: build-macos
|
||||||
runs-on: macos-11
|
runs-on: macos-10.15
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: '1.17'
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -31,30 +31,24 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: '1.19'
|
|
||||||
cache: true
|
|
||||||
- name: Cache LLVM source
|
- name: Cache LLVM source
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-14-macos-v1
|
key: llvm-source-13-macos-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- 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 LLVM build
|
- name: Cache LLVM build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-14-macos-v1
|
key: llvm-build-13-macos-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'
|
||||||
@@ -69,10 +63,10 @@ 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: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-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'
|
||||||
@@ -82,8 +76,6 @@ jobs:
|
|||||||
run: make test GOTESTFLAGS="-v -short"
|
run: make test GOTESTFLAGS="-v -short"
|
||||||
- name: Build TinyGo release tarball
|
- name: Build TinyGo release tarball
|
||||||
run: make release -j3
|
run: make release -j3
|
||||||
- name: Test stdlib packages
|
|
||||||
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-amd64.tar.gz
|
||||||
@@ -101,22 +93,3 @@ jobs:
|
|||||||
- name: Smoke tests
|
- name: Smoke tests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0
|
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0
|
||||||
test-macos-homebrew:
|
|
||||||
name: homebrew-install
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- name: Install LLVM
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@14
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Install Go
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: '1.19'
|
|
||||||
cache: true
|
|
||||||
- name: Build TinyGo
|
|
||||||
run: go install
|
|
||||||
- name: Check binary
|
|
||||||
run: tinygo version
|
|
||||||
|
|||||||
@@ -7,10 +7,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ dev, fix-docker-llvm-build ]
|
branches: [ dev, fix-docker-llvm-build ]
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push_to_registry:
|
push_to_registry:
|
||||||
name: build-push-dev
|
name: build-push-dev
|
||||||
@@ -55,35 +51,9 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
- name: Trigger Drivers repo build on Github Actions
|
- name: Trigger Drivers repo build on CircleCI
|
||||||
run: |
|
run: |
|
||||||
curl -X POST \
|
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/drivers/pipeline' \
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger Bluetooth repo build on Github Actions
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
|
|
||||||
-d '{"ref": "dev"}'
|
|
||||||
- name: Trigger TinyFS repo build on CircleCI
|
|
||||||
run: |
|
|
||||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfs/pipeline' \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
-d '{"branch": "dev"}' \
|
|
||||||
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
|
||||||
- name: Trigger TinyFont repo build on CircleCI
|
|
||||||
run: |
|
|
||||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfont/pipeline' \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
-d '{"branch": "dev"}' \
|
|
||||||
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
|
||||||
- name: Trigger TinyDraw repo build on CircleCI
|
|
||||||
run: |
|
|
||||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinydraw/pipeline' \
|
|
||||||
--header 'Content-Type: application/json' \
|
--header 'Content-Type: application/json' \
|
||||||
-d '{"branch": "dev"}' \
|
-d '{"branch": "dev"}' \
|
||||||
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
||||||
|
|||||||
+48
-257
@@ -7,57 +7,51 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- release
|
- release
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-linux:
|
build-linux:
|
||||||
# Build Linux binaries, ready for release.
|
# Build Linux binaries, ready for release.
|
||||||
# This runs inside an Alpine Linux container so we can more easily create a
|
# This intentionally uses an older Linux image, so that we compile against
|
||||||
# statically linked binary.
|
# an older glibc version and therefore are compatible with a wide range of
|
||||||
runs-on: ubuntu-latest
|
# Linux distributions.
|
||||||
container:
|
runs-on: ubuntu-18.04
|
||||||
image: golang:1.19-alpine
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install apk dependencies
|
|
||||||
# tar: needed for actions/cache@v3
|
|
||||||
# git+openssh: needed for checkout (I think?)
|
|
||||||
# ruby: needed to install fpm
|
|
||||||
run: apk add tar git openssh make g++ ruby
|
|
||||||
- name: Work around CVE-2022-24765
|
|
||||||
# We're not on a multi-user machine, so this is safe.
|
|
||||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Cache Go
|
- name: Install apt dependencies
|
||||||
uses: actions/cache@v3
|
run: |
|
||||||
|
sudo apt-get install --no-install-recommends \
|
||||||
|
ninja-build
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
go-version: '1.17'
|
||||||
|
- name: Cache Go
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
key: go-cache-linux-v1-${{ hashFiles('go.mod') }}
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
- name: Cache LLVM source
|
- name: Cache LLVM source
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-14-linux-alpine-v1
|
key: llvm-source-13-linux-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- 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 LLVM build
|
- name: Cache LLVM build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-14-linux-alpine-v1
|
key: llvm-build-13-linux-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'
|
||||||
@@ -65,46 +59,41 @@ jobs:
|
|||||||
# fetch LLVM source
|
# fetch LLVM source
|
||||||
rm -rf llvm-project
|
rm -rf llvm-project
|
||||||
make llvm-source
|
make llvm-source
|
||||||
# install dependencies
|
|
||||||
apk add cmake samurai python3
|
|
||||||
# build!
|
# build!
|
||||||
make llvm-build
|
make llvm-build
|
||||||
# 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: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-alpine-v1
|
key: binaryen-linux-v1
|
||||||
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: make binaryen
|
||||||
apk add cmake samurai python3
|
|
||||||
make binaryen STATIC=1
|
|
||||||
- name: Cache wasi-libc
|
- name: Cache wasi-libc
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-alpine-v1
|
key: wasi-libc-sysroot-linux-asserts-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'
|
||||||
run: make wasi-libc
|
run: make wasi-libc
|
||||||
- name: Install fpm
|
- name: Install fpm
|
||||||
run: |
|
run: |
|
||||||
gem install --version 4.0.7 public_suffix
|
sudo apt-get install ruby ruby-dev
|
||||||
gem install --version 2.7.6 dotenv
|
sudo gem install --no-document fpm
|
||||||
gem install --no-document fpm
|
|
||||||
- name: Build TinyGo release
|
- name: Build TinyGo release
|
||||||
run: |
|
run: |
|
||||||
make release deb -j3 STATIC=1
|
make release deb -j3
|
||||||
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@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: release-double-zipped
|
||||||
path: |
|
path: |
|
||||||
/tmp/tinygo.linux-amd64.tar.gz
|
/tmp/tinygo.linux-amd64.tar.gz
|
||||||
/tmp/tinygo_amd64.deb
|
/tmp/tinygo_amd64.deb
|
||||||
@@ -116,10 +105,9 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.19'
|
go-version: '1.17'
|
||||||
cache: true
|
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||||
@@ -127,7 +115,7 @@ jobs:
|
|||||||
- name: Download release artifact
|
- name: Download release artifact
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: release-double-zipped
|
||||||
- name: Extract release tarball
|
- name: Extract release tarball
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/lib
|
mkdir -p ~/lib
|
||||||
@@ -169,37 +157,42 @@ jobs:
|
|||||||
simavr \
|
simavr \
|
||||||
ninja-build
|
ninja-build
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.19'
|
go-version: '1.17'
|
||||||
cache: true
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '12'
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
|
- name: Cache Go
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
key: go-cache-linux-asserts-v1-${{ hashFiles('go.mod') }}
|
||||||
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
- name: Cache LLVM source
|
- name: Cache LLVM source
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-14-linux-asserts-v2
|
key: llvm-source-13-linux-asserts-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- 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 LLVM build
|
- name: Cache LLVM build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-14-linux-asserts-v1
|
key: llvm-build-13-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'
|
||||||
@@ -212,7 +205,7 @@ 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: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-asserts-v1
|
key: binaryen-linux-asserts-v1
|
||||||
@@ -221,10 +214,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@v2
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-asserts-v5
|
key: wasi-libc-sysroot-linux-asserts-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'
|
||||||
@@ -236,8 +229,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make ASSERT=1
|
make ASSERT=1
|
||||||
echo "$(pwd)/build" >> $GITHUB_PATH
|
echo "$(pwd)/build" >> $GITHUB_PATH
|
||||||
- name: Test machine package
|
|
||||||
run: make check-machine
|
|
||||||
- name: Test stdlib packages
|
- name: Test stdlib packages
|
||||||
run: make tinygo-test
|
run: make tinygo-test
|
||||||
- name: Install Xtensa toolchain
|
- name: Install Xtensa toolchain
|
||||||
@@ -248,203 +239,3 @@ jobs:
|
|||||||
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
|
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
|
||||||
- run: make smoketest
|
- run: make smoketest
|
||||||
- run: make wasmtest
|
- run: make wasmtest
|
||||||
- run: make tinygo-baremetal
|
|
||||||
build-linux-arm:
|
|
||||||
# Build ARM Linux binaries, ready for release.
|
|
||||||
# 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
|
|
||||||
# Linux distributions.
|
|
||||||
# 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-18.04
|
|
||||||
needs: build-linux
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Install apt dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install --no-install-recommends \
|
|
||||||
qemu-user \
|
|
||||||
g++-arm-linux-gnueabihf \
|
|
||||||
libc6-dev-armhf-cross
|
|
||||||
- name: Install Go
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: '1.19'
|
|
||||||
cache: true
|
|
||||||
- name: Cache LLVM source
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache-llvm-source
|
|
||||||
with:
|
|
||||||
key: llvm-source-14-linux-v2
|
|
||||||
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: Cache LLVM build
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache-llvm-build
|
|
||||||
with:
|
|
||||||
key: llvm-build-14-linux-arm-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
|
|
||||||
# Install build dependencies.
|
|
||||||
sudo apt-get install --no-install-recommends ninja-build
|
|
||||||
# build!
|
|
||||||
make llvm-build CROSS=arm-linux-gnueabihf
|
|
||||||
# Remove unnecessary object files (to reduce cache size).
|
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
|
||||||
- name: Cache Binaryen
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache-binaryen
|
|
||||||
with:
|
|
||||||
key: binaryen-linux-arm-v1
|
|
||||||
path: build/wasm-opt
|
|
||||||
- name: Build Binaryen
|
|
||||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
sudo apt-get install --no-install-recommends ninja-build
|
|
||||||
git submodule update --init lib/binaryen
|
|
||||||
make CROSS=arm-linux-gnueabihf 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=arm-linux-gnueabihf
|
|
||||||
- name: Download amd64 release
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
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 arm release
|
|
||||||
run: |
|
|
||||||
make release deb RELEASEONLY=1 DEB_ARCH=armhf
|
|
||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-arm.tar.gz
|
|
||||||
cp -p build/release.deb /tmp/tinygo_armhf.deb
|
|
||||||
- name: Publish release artifact
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: linux-arm-double-zipped
|
|
||||||
path: |
|
|
||||||
/tmp/tinygo.linux-arm.tar.gz
|
|
||||||
/tmp/tinygo_armhf.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-18.04
|
|
||||||
needs: build-linux
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- 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.19'
|
|
||||||
cache: true
|
|
||||||
- name: Cache LLVM source
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache-llvm-source
|
|
||||||
with:
|
|
||||||
key: llvm-source-14-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: Cache LLVM build
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache-llvm-build
|
|
||||||
with:
|
|
||||||
key: llvm-build-14-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: 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@v2
|
|
||||||
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@v2
|
|
||||||
with:
|
|
||||||
name: linux-arm64-double-zipped
|
|
||||||
path: |
|
|
||||||
/tmp/tinygo.linux-arm64.tar.gz
|
|
||||||
/tmp/tinygo_arm64.deb
|
|
||||||
|
|||||||
@@ -7,17 +7,15 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- release
|
- release
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: brechtm/setup-scoop@v2
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
scoop_update: 'false'
|
go-version: '1.17'
|
||||||
|
- uses: MinoruSekine/setup-scoop@v1
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -26,30 +24,31 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Cache Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.19'
|
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
|
||||||
cache: true
|
path: |
|
||||||
|
~/AppData/Local/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
- name: Cache LLVM source
|
- name: Cache LLVM source
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-14-windows-v2
|
key: llvm-source-13-windows-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
llvm-project/compiler-rt
|
|
||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- 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 LLVM build
|
- name: Cache LLVM build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-14-windows-v2
|
key: llvm-build-13-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'
|
||||||
@@ -59,26 +58,22 @@ jobs:
|
|||||||
rm -rf llvm-project
|
rm -rf llvm-project
|
||||||
make llvm-source
|
make llvm-source
|
||||||
# build!
|
# build!
|
||||||
make llvm-build CCACHE=OFF
|
make llvm-build
|
||||||
# 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: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-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'
|
||||||
run: make wasi-libc
|
run: make wasi-libc
|
||||||
- name: Install wasmtime
|
|
||||||
run: |
|
|
||||||
scoop install wasmtime
|
|
||||||
- name: Test TinyGo
|
- name: Test TinyGo
|
||||||
shell: bash
|
shell: bash
|
||||||
run: make test GOTESTFLAGS="-v -short"
|
run: make test GOTESTFLAGS="-v -short"
|
||||||
- name: Build TinyGo release tarball
|
- name: Build TinyGo release tarball
|
||||||
shell: bash
|
|
||||||
run: make build/release -j4
|
run: make build/release -j4
|
||||||
- name: Make release artifact
|
- name: Make release artifact
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -100,5 +95,3 @@ jobs:
|
|||||||
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
|
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
|
||||||
- name: Test stdlib packages
|
- name: Test stdlib packages
|
||||||
run: make tinygo-test
|
run: make tinygo-test
|
||||||
- name: Test stdlib packages on wasi
|
|
||||||
run: make tinygo-test-wasi-fast
|
|
||||||
|
|||||||
+1
-2
@@ -23,7 +23,6 @@ llvm-project
|
|||||||
build/*
|
build/*
|
||||||
|
|
||||||
# Ignore files generated by smoketest
|
# Ignore files generated by smoketest
|
||||||
test
|
|
||||||
test.bin
|
test.bin
|
||||||
test.elf
|
test.elf
|
||||||
test.exe
|
test.exe
|
||||||
@@ -31,4 +30,4 @@ test.gba
|
|||||||
test.hex
|
test.hex
|
||||||
test.nro
|
test.nro
|
||||||
test.wasm
|
test.wasm
|
||||||
wasm.wasm
|
wasm.wasm
|
||||||
+4
-3
@@ -10,6 +10,10 @@
|
|||||||
[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/tinygo-org/cmsis-svd
|
||||||
|
[submodule "lib/compiler-rt"]
|
||||||
|
path = lib/compiler-rt
|
||||||
|
url = https://github.com/llvm-mirror/compiler-rt.git
|
||||||
|
branch = release_80
|
||||||
[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/CraneStation/wasi-libc
|
||||||
@@ -28,6 +32,3 @@
|
|||||||
[submodule "lib/mingw-w64"]
|
[submodule "lib/mingw-w64"]
|
||||||
path = lib/mingw-w64
|
path = lib/mingw-w64
|
||||||
url = https://github.com/mingw-w64/mingw-w64.git
|
url = https://github.com/mingw-w64/mingw-w64.git
|
||||||
[submodule "lib/macos-minimal-sdk"]
|
|
||||||
path = lib/macos-minimal-sdk
|
|
||||||
url = https://github.com/aykevl/macos-minimal-sdk.git
|
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ 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.15+)
|
||||||
* Standard build tools (gcc/clang)
|
* Standard build tools (gcc/clang)
|
||||||
* git
|
* git
|
||||||
* CMake
|
* CMake
|
||||||
|
|||||||
-205
@@ -1,208 +1,3 @@
|
|||||||
0.25.0
|
|
||||||
---
|
|
||||||
|
|
||||||
* **command line**
|
|
||||||
- change to ignore PortReset failures
|
|
||||||
* **compiler**
|
|
||||||
- `compiler`: darwin/arm64 is aarch64, not arm
|
|
||||||
- `compiler`: don't clobber X18 and FP registers on darwin/arm64
|
|
||||||
- `compiler`: fix issue with methods on generic structs
|
|
||||||
- `compiler`: do not try to build generic functions
|
|
||||||
- `compiler`: fix type names for generic named structs
|
|
||||||
- `compiler`: fix multiple defined function issue for generic functions
|
|
||||||
- `compiler`: implement `unsafe.Alignof` and `unsafe.Sizeof` for generic code
|
|
||||||
* **standard library**
|
|
||||||
- `machine`: add DTR and RTS to Serialer interface
|
|
||||||
- `machine`: reorder pin definitions to improve pin list on tinygo.org
|
|
||||||
- `machine/usb`: add support for MIDI
|
|
||||||
- `machine/usb`: adjust buffer alignment (samd21, samd51, nrf52840)
|
|
||||||
- `machine/usb/midi`: add `NoteOn`, `NoteOff`, and `SendCC` methods
|
|
||||||
- `machine/usb/midi`: add definition of MIDI note number
|
|
||||||
- `runtime`: add benchmarks for memhash
|
|
||||||
- `runtime`: add support for printing slices via print/println
|
|
||||||
* **targets**
|
|
||||||
- `avr`: fix some apparent mistake in atmega1280/atmega2560 pin constants
|
|
||||||
- `esp32`: provide hardware pin constants
|
|
||||||
- `esp32`: fix WDT reset on the MCH2022 badge
|
|
||||||
- `esp32`: optimize SPI transmit
|
|
||||||
- `esp32c3`: provide hardware pin constants
|
|
||||||
- `esp8266`: provide hardware pin constants like `GPIO2`
|
|
||||||
- `nrf51`: define and use `P0_xx` constants
|
|
||||||
- `nrf52840`, `samd21`, `samd51`: unify bootloader entry process
|
|
||||||
- `nrf52840`, `samd21`, `samd51`: change usbSetup and sendZlp to public
|
|
||||||
- `nrf52840`, `samd21`, `samd51`: refactor handleStandardSetup and initEndpoint
|
|
||||||
- `nrf52840`, `samd21`, `samd51`: improve usb-device initialization
|
|
||||||
- `nrf52840`, `samd21`, `samd51`: move usbcdc to machine/usb/cdc
|
|
||||||
- `rp2040`: add usb serial vendor/product ID
|
|
||||||
- `rp2040`: add support for usb
|
|
||||||
- `rp2040`: change default for serial to usb
|
|
||||||
- `rp2040`: add support for `machine.EnterBootloader`
|
|
||||||
- `rp2040`: turn off pullup/down when input type is not specified
|
|
||||||
- `rp2040`: make picoprobe default openocd interface
|
|
||||||
- `samd51`: add support for `DAC1`
|
|
||||||
- `samd51`: improve TRNG
|
|
||||||
- `wasm`: stub `runtime.buffered`, `runtime.getchar`
|
|
||||||
- `wasi`: make leveldb runtime hash the default
|
|
||||||
* **boards**
|
|
||||||
- add Challenger RP2040 LoRa
|
|
||||||
- add MCH2022 badge
|
|
||||||
- add XIAO RP2040
|
|
||||||
- `clue`: remove pins `D21`..`D28`
|
|
||||||
- `feather-rp2040`, `macropad-rp2040`: fix qspi-flash settings
|
|
||||||
- `xiao-ble`: add support for flash-1200-bps-reset
|
|
||||||
- `gopherbot`, `gopherbot2`: add these aliases to simplify for newer users
|
|
||||||
|
|
||||||
|
|
||||||
0.24.0
|
|
||||||
---
|
|
||||||
|
|
||||||
* **command line**
|
|
||||||
- remove support for go 1.15
|
|
||||||
- remove support for LLVM 11 and LLVM 12
|
|
||||||
- add initial Go 1.19 beta support
|
|
||||||
- `test`: fix package/... syntax
|
|
||||||
* **compiler**
|
|
||||||
- add support for the embed package
|
|
||||||
- `builder`: improve error message for "command not found"
|
|
||||||
- `builder`: add support for ThinLTO on MacOS and Windows
|
|
||||||
- `builder`: free LLVM objects after use, to reduce memory leaking
|
|
||||||
- `builder`: improve `-no-debug` error messages
|
|
||||||
- `cgo`: be more strict: CGo now requires every Go file to import the headers it needs
|
|
||||||
- `compiler`: alignof(func) is 1 pointer, not 2
|
|
||||||
- `compiler`: add support for type parameters (aka generics)
|
|
||||||
- `compiler`: implement `recover()` built-in function
|
|
||||||
- `compiler`: support atomic, volatile, and LLVM memcpy-like functions in defer
|
|
||||||
- `compiler`: drop support for macos syscalls via inline assembly
|
|
||||||
- `interp`: do not try to interpret past task.Pause()
|
|
||||||
- `interp`: fix some buggy localValue handling
|
|
||||||
- `interp`: do not unroll loops
|
|
||||||
- `transform`: fix MakeGCStackSlots that caused a possible GC bug on WebAssembly
|
|
||||||
* **standard library**
|
|
||||||
- `os`: enable os.Stdin for baremetal target
|
|
||||||
- `reflect`: add `Value.UnsafePointer` method
|
|
||||||
- `runtime`: scan GC globals conservatively on Windows, MacOS, Linux and Nintendo Switch
|
|
||||||
- `runtime`: add per-map hash seeds
|
|
||||||
- `runtime`: handle nil map write panics
|
|
||||||
- `runtime`: add stronger hash functions
|
|
||||||
- `syscall`: implement `Getpagesize`
|
|
||||||
* **targets**
|
|
||||||
- `atmega2560`: support UART1-3 + example for uart
|
|
||||||
- `avr`: use compiler-rt for improved float64 support
|
|
||||||
- `avr`: simplify timer-based time
|
|
||||||
- `avr`: fix race condition in stack write
|
|
||||||
- `darwin`: add support for `GOARCH=arm64` (aka Apple Silicon)
|
|
||||||
- `darwin`: support `-size=short` and `-size=full` flag
|
|
||||||
- `rp2040`: replace sleep 'busy loop' with timer alarm
|
|
||||||
- `rp2040`: align api for `PortMaskSet`, `PortMaskClear`
|
|
||||||
- `rp2040`: fix GPIO interrupts
|
|
||||||
- `samd21`, `samd51`, `nrf52840`: add support for USBHID (keyboard / mouse)
|
|
||||||
- `wasm`: update wasi-libc version
|
|
||||||
- `wasm`: use newer WebAssembly features
|
|
||||||
* **boards**
|
|
||||||
- add Badger 2040
|
|
||||||
- `matrixportal-m4`: attach USB DP to the correct pin
|
|
||||||
- `teensy40`: add I2C support
|
|
||||||
- `wioterminal`: fix I2C definition
|
|
||||||
|
|
||||||
|
|
||||||
0.23.0
|
|
||||||
---
|
|
||||||
|
|
||||||
* **command line**
|
|
||||||
- add `-work` flag
|
|
||||||
- add Go 1.18 support
|
|
||||||
- add LLVM 14 support
|
|
||||||
- `run`: add support for command-line parameters
|
|
||||||
- `build`: calculate default output path if `-o` is not specified
|
|
||||||
- `build`: add JSON output
|
|
||||||
- `test`: support multiple test binaries with `-c`
|
|
||||||
- `test`: support flags like `-v` on all targets (including emulated firmware)
|
|
||||||
* **compiler**
|
|
||||||
- add support for ThinLTO
|
|
||||||
- use compiler-rt from LLVM
|
|
||||||
- `builder`: prefer GNU build ID over Go build ID for caching
|
|
||||||
- `builder`: add support for cross compiling to Darwin
|
|
||||||
- `builder`: support machine outlining pass in stacksize calculation
|
|
||||||
- `builder`: disable asynchronous unwind tables
|
|
||||||
- `compileopts`: fix emulator configuration on non-amd64 Linux architectures
|
|
||||||
- `compiler`: move allocations > 256 bytes to the heap
|
|
||||||
- `compiler`: fix incorrect `unsafe.Alignof` on some 32-bit architectures
|
|
||||||
- `compiler`: accept alias for slice `cap` builtin
|
|
||||||
- `compiler`: allow slices of empty structs
|
|
||||||
- `compiler`: fix difference in aliases in interface methods
|
|
||||||
- `compiler`: make `RawSyscall` an alias for `Syscall`
|
|
||||||
- `compiler`: remove support for memory references in `AsmFull`
|
|
||||||
- `loader`: only add Clang header path for CGo
|
|
||||||
- `transform`: fix poison value in heap-to-stack transform
|
|
||||||
* **standard library**
|
|
||||||
- `internal/fuzz`: add this package as a shim
|
|
||||||
- `os`: implement readdir for darwin and linux
|
|
||||||
- `os`: add `DirFS`, which is used by many programs to access readdir.
|
|
||||||
- `os`: isWine: be compatible with older versions of wine, too
|
|
||||||
- `os`: implement `RemoveAll`
|
|
||||||
- `os`: Use a `uintptr` for `NewFile`
|
|
||||||
- `os`: add stubs for `exec.ExitError` and `ProcessState.ExitCode`
|
|
||||||
- `os`: export correct values for `DevNull` for each OS
|
|
||||||
- `os`: improve support for `Signal` by fixing various bugs
|
|
||||||
- `os`: implement `File.Fd` method
|
|
||||||
- `os`: implement `UserHomeDir`
|
|
||||||
- `os`: add `exec.ProcessState` stub
|
|
||||||
- `os`: implement `Pipe` for darwin
|
|
||||||
- `os`: define stub `ErrDeadlineExceeded`
|
|
||||||
- `reflect`: add stubs for more missing methods
|
|
||||||
- `reflect`: rename `reflect.Ptr` to `reflect.Pointer`
|
|
||||||
- `reflect`: add `Value.FieldByIndexErr` stub
|
|
||||||
- `runtime`: fix various small GC bugs
|
|
||||||
- `runtime`: use memzero for leaking collector instead of manually zeroing objects
|
|
||||||
- `runtime`: implement `memhash`
|
|
||||||
- `runtime`: implement `fastrand`
|
|
||||||
- `runtime`: add stub for `debug.ReadBuildInfo`
|
|
||||||
- `runtime`: add stub for `NumCPU`
|
|
||||||
- `runtime`: don't inline `runtime.alloc` with `-gc=leaking`
|
|
||||||
- `runtime`: add `Version`
|
|
||||||
- `runtime`: add stubs for `NumCgoCall` and `NumGoroutine`
|
|
||||||
- `runtime`: stub {Lock,Unlock}OSThread on Windows
|
|
||||||
- `runtime`: be able to deal with a very small heap
|
|
||||||
- `syscall`: make `Environ` return a copy of the environment
|
|
||||||
- `syscall`: implement getpagesize and munmap
|
|
||||||
- `syscall`: `wasi`: define `MAP_SHARED` and `PROT_READ`
|
|
||||||
- `syscall`: stub mmap(), munmap(), MAP_SHARED, PROT_READ, SIGBUS, etc. on nonhosted targets
|
|
||||||
- `syscall`: darwin: more complete list of signals
|
|
||||||
- `syscall`: `wasi`: more complete list of signals
|
|
||||||
- `syscall`: stub `WaitStatus`
|
|
||||||
- `syscall/js`: allow copyBytesTo(Go|JS) to use `Uint8ClampedArray`
|
|
||||||
- `testing`: implement `TempDir`
|
|
||||||
- `testing`: nudge type TB closer to upstream; should be a no-op change.
|
|
||||||
- `testing`: on baremetal platforms, use simpler test matcher
|
|
||||||
* **targets**
|
|
||||||
- `atsamd`: fix usbcdc initialization when `-serial=uart`
|
|
||||||
- `atsamd51`: allow higher frequency when using SPI
|
|
||||||
- `esp`: support CGo
|
|
||||||
- `esp32c3`: add support for input pin
|
|
||||||
- `esp32c3`: add support for GPIO interrupts
|
|
||||||
- `esp32c3`: add support to receive UART data
|
|
||||||
- `rp2040`: fix PWM bug at high frequency
|
|
||||||
- `rp2040`: fix some minor I2C bugs
|
|
||||||
- `rp2040`: fix incorrect inline assembly
|
|
||||||
- `rp2040`: fix spurious i2c STOP during write+read transaction
|
|
||||||
- `rp2040`: improve ADC support
|
|
||||||
- `wasi`: remove `--export-dynamic` linker flag
|
|
||||||
- `wasm`: remove heap allocator from wasi-libc
|
|
||||||
* **boards**
|
|
||||||
- `circuitplay-bluefruit`: move pin mappings so board can be compiled for WASM use in Playground
|
|
||||||
- `esp32-c3-12f`: add the ESP32-C3-12f Kit
|
|
||||||
- `m5stamp-c3`: add pin setting of UART
|
|
||||||
- `macropad-rp2040`: add the Adafruit MacroPad RP2040 board
|
|
||||||
- `nano-33-ble`: typo in LPS22HB peripheral definition and documentation (#2579)
|
|
||||||
- `teensy41`: add the Teensy 4.1 board
|
|
||||||
- `teensy40`: add ADC support
|
|
||||||
- `teensy40`: add SPI support
|
|
||||||
- `thingplus-rp2040`: add the SparkFun Thing Plus RP2040 board
|
|
||||||
- `wioterminal`: add DefaultUART
|
|
||||||
- `wioterminal`: verify written data when flashing through OpenOCD
|
|
||||||
- `xiao-ble`: add XIAO BLE nRF52840 support
|
|
||||||
|
|
||||||
|
|
||||||
0.22.0
|
0.22.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||||
FROM golang:1.19 AS tinygo-llvm
|
FROM golang:1.17 AS tinygo-llvm
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
|
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
|
||||||
|
|||||||
@@ -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 = 14 13 12 11
|
LLVM_VERSIONS = 13 12 11
|
||||||
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)
|
||||||
@@ -38,16 +38,10 @@ 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)
|
||||||
|
|
||||||
# Check for ccache if the user hasn't set it to on or off.
|
# Use CCACHE for LLVM if possible
|
||||||
ifeq (, $(CCACHE))
|
ifneq (, $(shell command -v ccache 2> /dev/null))
|
||||||
# Use CCACHE for LLVM if possible
|
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=ON'
|
||||||
ifneq (, $(shell command -v ccache 2> /dev/null))
|
|
||||||
CCACHE := ON
|
|
||||||
else
|
|
||||||
CCACHE := OFF
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=$(CCACHE)'
|
|
||||||
|
|
||||||
# Allow enabling LLVM assertions
|
# Allow enabling LLVM assertions
|
||||||
ifeq (1, $(ASSERT))
|
ifeq (1, $(ASSERT))
|
||||||
@@ -56,55 +50,6 @@ else
|
|||||||
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (1, $(STATIC))
|
|
||||||
# Build TinyGo as a fully statically linked binary (no dynamically loaded
|
|
||||||
# libraries such as a libc). This is not supported with glibc which is used
|
|
||||||
# on most major Linux distributions. However, it is supported in Alpine
|
|
||||||
# Linux with musl.
|
|
||||||
CGO_LDFLAGS += -static
|
|
||||||
# Also set the thread stack size to 1MB. This is necessary on musl as the
|
|
||||||
# default stack size is 128kB and LLVM uses more than that.
|
|
||||||
# For more information, see:
|
|
||||||
# https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size
|
|
||||||
CGO_LDFLAGS += -Wl,-z,stack-size=1048576
|
|
||||||
# Build wasm-opt with static linking.
|
|
||||||
# For details, see:
|
|
||||||
# https://github.com/WebAssembly/binaryen/blob/version_102/.github/workflows/ci.yml#L181
|
|
||||||
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Cross compiling support.
|
|
||||||
ifneq ($(CROSS),)
|
|
||||||
CC = $(CROSS)-gcc
|
|
||||||
CXX = $(CROSS)-g++
|
|
||||||
LLVM_OPTION += \
|
|
||||||
-DCMAKE_C_COMPILER=$(CC) \
|
|
||||||
-DCMAKE_CXX_COMPILER=$(CXX) \
|
|
||||||
-DLLVM_DEFAULT_TARGET_TRIPLE=$(CROSS) \
|
|
||||||
-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-UCMAKE_C_COMPILER;-UCMAKE_CXX_COMPILER"
|
|
||||||
ifeq ($(CROSS), arm-linux-gnueabihf)
|
|
||||||
# Assume we're building on a Debian-like distro, with QEMU installed.
|
|
||||||
LLVM_CONFIG_PREFIX = qemu-arm -L /usr/arm-linux-gnueabihf/
|
|
||||||
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
|
|
||||||
LLVM_OPTION += \
|
|
||||||
-DCMAKE_SYSTEM_NAME=Linux \
|
|
||||||
-DLLVM_TARGET_ARCH=ARM
|
|
||||||
GOENVFLAGS = GOARCH=arm CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
|
|
||||||
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
|
|
||||||
else ifeq ($(CROSS), aarch64-linux-gnu)
|
|
||||||
# Assume we're building on a Debian-like distro, with QEMU installed.
|
|
||||||
LLVM_CONFIG_PREFIX = qemu-aarch64 -L /usr/aarch64-linux-gnu/
|
|
||||||
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
|
|
||||||
LLVM_OPTION += \
|
|
||||||
-DCMAKE_SYSTEM_NAME=Linux \
|
|
||||||
-DLLVM_TARGET_ARCH=AArch64
|
|
||||||
GOENVFLAGS = GOARCH=arm64 CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
|
|
||||||
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
|
|
||||||
else
|
|
||||||
$(error Unknown cross compilation target: $(CROSS))
|
|
||||||
endif
|
|
||||||
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 frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsmanifest
|
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsmanifest
|
||||||
@@ -128,8 +73,6 @@ ifeq ($(OS),Windows_NT)
|
|||||||
else ifeq ($(shell uname -s),Darwin)
|
else ifeq ($(shell uname -s),Darwin)
|
||||||
MD5SUM = md5
|
MD5SUM = md5
|
||||||
|
|
||||||
CGO_LDFLAGS += -lxar
|
|
||||||
|
|
||||||
USE_SYSTEM_BINARYEN ?= 1
|
USE_SYSTEM_BINARYEN ?= 1
|
||||||
|
|
||||||
else ifeq ($(shell uname -s),FreeBSD)
|
else ifeq ($(shell uname -s),FreeBSD)
|
||||||
@@ -146,11 +89,11 @@ CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGe
|
|||||||
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.
|
||||||
LLD_LIB_NAMES = lldCOFF lldCommon lldELF lldMachO lldMinGW lldWasm
|
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO lldMinGW lldReaderWriter lldWasm lldYAML
|
||||||
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
|
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
|
||||||
|
|
||||||
# Other libraries that are needed to link TinyGo.
|
# Other libraries that are needed to link TinyGo.
|
||||||
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMX86TargetMCA
|
EXTRA_LIB_NAMES = LLVMInterpreter
|
||||||
|
|
||||||
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
|
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
|
||||||
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
|
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
|
||||||
@@ -165,15 +108,15 @@ NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(ad
|
|||||||
|
|
||||||
# For static linking.
|
# For static linking.
|
||||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||||
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
CGO_CPPFLAGS+=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
||||||
CGO_CXXFLAGS=-std=c++14
|
CGO_CXXFLAGS=-std=c++14
|
||||||
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf build
|
@rm -rf build
|
||||||
|
|
||||||
FMT_PATHS = ./*.go builder cgo/*.go compiler interp loader src transform
|
FMT_PATHS = ./*.go builder cgo compiler interp loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall src/testing src/internal/reflectlite transform
|
||||||
fmt:
|
fmt:
|
||||||
@gofmt -l -w $(FMT_PATHS)
|
@gofmt -l -w $(FMT_PATHS)
|
||||||
fmt-check:
|
fmt-check:
|
||||||
@@ -230,12 +173,12 @@ gen-device-rp: build/gen-device-svd
|
|||||||
|
|
||||||
# Get LLVM sources.
|
# Get LLVM sources.
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
git clone -b xtensa_release_14.0.0-patched --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
git clone -b xtensa_release_13.0.0 --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.
|
||||||
TINYGO_SOURCE_DIR=$(shell pwd)
|
TINYGO_SOURCE_DIR=$(shell pwd)
|
||||||
$(LLVM_BUILDDIR)/build.ninja:
|
$(LLVM_BUILDDIR)/build.ninja: llvm-source
|
||||||
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
|
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
|
||||||
|
|
||||||
# Build LLVM.
|
# Build LLVM.
|
||||||
@@ -257,41 +200,31 @@ 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 WASM_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 WASM_CFLAGS="-O2 -g -DNDEBUG" WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
|
||||||
|
|
||||||
|
|
||||||
# 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)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
|
||||||
|
|
||||||
test: wasi-libc
|
test: wasi-libc
|
||||||
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 ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||||
|
|
||||||
# Check whether the machine package matches the documentation.
|
# Tests that take over a minute in wasi
|
||||||
# TODO: improve `tinygo targets` so it doesn't return these invalid targets.
|
|
||||||
CHECK_MACHINE_EXCULDE = \
|
|
||||||
cortex-m-qemu \
|
|
||||||
particle-3rd-gen \
|
|
||||||
riscv-qemu \
|
|
||||||
riscv64-qemu \
|
|
||||||
rp2040 \
|
|
||||||
$(nil)
|
|
||||||
check-machine:
|
|
||||||
$(GO) run ./tools/machinecheck $(filter-out $(CHECK_MACHINE_EXCULDE),$(shell $(TINYGO) targets))
|
|
||||||
|
|
||||||
# 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 = \
|
||||||
compress/bzip2 \
|
compress/bzip2 \
|
||||||
|
compress/flate \
|
||||||
crypto/dsa \
|
crypto/dsa \
|
||||||
index/suffixarray \
|
index/suffixarray \
|
||||||
|
|
||||||
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
|
TEST_PACKAGES_BASE = \
|
||||||
TEST_PACKAGES_FAST = \
|
|
||||||
compress/zlib \
|
compress/zlib \
|
||||||
container/heap \
|
container/heap \
|
||||||
container/list \
|
container/list \
|
||||||
container/ring \
|
container/ring \
|
||||||
crypto/des \
|
crypto/des \
|
||||||
|
crypto/elliptic/internal/fiat \
|
||||||
crypto/internal/subtle \
|
crypto/internal/subtle \
|
||||||
crypto/md5 \
|
crypto/md5 \
|
||||||
crypto/rc4 \
|
crypto/rc4 \
|
||||||
@@ -299,7 +232,6 @@ TEST_PACKAGES_FAST = \
|
|||||||
crypto/sha256 \
|
crypto/sha256 \
|
||||||
crypto/sha512 \
|
crypto/sha512 \
|
||||||
debug/macho \
|
debug/macho \
|
||||||
embed/internal/embedtest \
|
|
||||||
encoding \
|
encoding \
|
||||||
encoding/ascii85 \
|
encoding/ascii85 \
|
||||||
encoding/base32 \
|
encoding/base32 \
|
||||||
@@ -315,7 +247,6 @@ TEST_PACKAGES_FAST = \
|
|||||||
internal/profile \
|
internal/profile \
|
||||||
math \
|
math \
|
||||||
math/cmplx \
|
math/cmplx \
|
||||||
net \
|
|
||||||
net/http/internal/ascii \
|
net/http/internal/ascii \
|
||||||
net/mail \
|
net/mail \
|
||||||
os \
|
os \
|
||||||
@@ -328,99 +259,41 @@ TEST_PACKAGES_FAST = \
|
|||||||
unicode \
|
unicode \
|
||||||
unicode/utf16 \
|
unicode/utf16 \
|
||||||
unicode/utf8 \
|
unicode/utf8 \
|
||||||
$(nil)
|
|
||||||
|
|
||||||
# Assume this will go away before Go2, so only check minor version.
|
# Standard library packages that pass tests natively
|
||||||
ifeq ($(filter $(shell $(GO) env GOVERSION | cut -f 2 -d.), 16 17 18), )
|
TEST_PACKAGES := \
|
||||||
TEST_PACKAGES_FAST += crypto/internal/nistec/fiat
|
$(TEST_PACKAGES_BASE)
|
||||||
else
|
|
||||||
TEST_PACKAGES_FAST += crypto/elliptic/internal/fiat
|
# archive/zip requires ReadAt, which is not yet supported on windows
|
||||||
|
ifneq ($(OS),Windows_NT)
|
||||||
|
TEST_PACKAGES := \
|
||||||
|
$(TEST_PACKAGES) \
|
||||||
|
archive/zip
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
# Standard library packages that pass tests on wasi
|
||||||
# compress/flate appears to hang on wasi
|
TEST_PACKAGES_WASI = \
|
||||||
# compress/lzw appears to hang on wasi
|
$(TEST_PACKAGES_BASE)
|
||||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
|
||||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
|
||||||
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
|
|
||||||
# strconv requires recover() which is not yet supported on wasi
|
|
||||||
# text/template/parse requires recover(), which is not yet supported on wasi
|
|
||||||
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
|
|
||||||
|
|
||||||
# Additional standard library packages that pass tests on individual platforms
|
|
||||||
TEST_PACKAGES_LINUX := \
|
|
||||||
archive/zip \
|
|
||||||
compress/flate \
|
|
||||||
compress/lzw \
|
|
||||||
crypto/hmac \
|
|
||||||
debug/dwarf \
|
|
||||||
debug/plan9obj \
|
|
||||||
io/ioutil \
|
|
||||||
strconv \
|
|
||||||
testing/fstest \
|
|
||||||
text/template/parse
|
|
||||||
|
|
||||||
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
|
||||||
|
|
||||||
TEST_PACKAGES_WINDOWS := \
|
|
||||||
compress/flate \
|
|
||||||
compress/lzw \
|
|
||||||
crypto/hmac \
|
|
||||||
strconv \
|
|
||||||
text/template/parse \
|
|
||||||
$(nil)
|
|
||||||
|
|
||||||
# Report platforms on which each standard library package is known to pass tests
|
|
||||||
jointmp := $(shell echo /tmp/join.$$$$)
|
|
||||||
report-stdlib-tests-pass:
|
|
||||||
@for t in $(TEST_PACKAGES_DARWIN); do echo "$$t darwin"; done | sort > $(jointmp).darwin
|
|
||||||
@for t in $(TEST_PACKAGES_LINUX); do echo "$$t linux"; done | sort > $(jointmp).linux
|
|
||||||
@for t in $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW); do echo "$$t darwin linux wasi windows"; done | sort > $(jointmp).portable
|
|
||||||
@join -a1 -a2 $(jointmp).darwin $(jointmp).linux | \
|
|
||||||
join -a1 -a2 - $(jointmp).portable
|
|
||||||
@rm $(jointmp).*
|
|
||||||
|
|
||||||
# Standard library packages that pass tests quickly on the current platform
|
|
||||||
ifeq ($(shell uname),Darwin)
|
|
||||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
|
|
||||||
TEST_IOFS := true
|
|
||||||
endif
|
|
||||||
ifeq ($(shell uname),Linux)
|
|
||||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
|
|
||||||
TEST_IOFS := true
|
|
||||||
endif
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
|
||||||
TEST_IOFS := false
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Test known-working standard library packages.
|
# Test known-working standard library packages.
|
||||||
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
||||||
.PHONY: tinygo-test
|
.PHONY: tinygo-test
|
||||||
tinygo-test:
|
tinygo-test:
|
||||||
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test $(TEST_PACKAGES) $(TEST_PACKAGES_SLOW)
|
||||||
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
|
|
||||||
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
|
||||||
@# For more details, see the comments on issue #3143.
|
|
||||||
ifeq ($(TEST_IOFS),true)
|
|
||||||
$(TINYGO) test -stack-size=6MB io/fs
|
|
||||||
endif
|
|
||||||
tinygo-test-fast:
|
tinygo-test-fast:
|
||||||
$(TINYGO) test $(TEST_PACKAGES_HOST)
|
$(TINYGO) test $(TEST_PACKAGES)
|
||||||
tinygo-bench:
|
tinygo-bench:
|
||||||
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -bench . $(TEST_PACKAGES) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-bench-fast:
|
tinygo-bench-fast:
|
||||||
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
|
$(TINYGO) test -bench . $(TEST_PACKAGES)
|
||||||
|
|
||||||
# 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 wasi $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-test-wasi-fast:
|
tinygo-test-wasi-fast:
|
||||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
$(TINYGO) test -target wasi $(TEST_PACKAGES_WASI)
|
||||||
tinygo-bench-wasi:
|
tinygo-bench-wasi:
|
||||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-bench-wasi-fast:
|
tinygo-bench-wasi-fast:
|
||||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
|
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI)
|
||||||
|
|
||||||
# Test external packages in a large corpus.
|
# Test external packages in a large corpus.
|
||||||
test-corpus:
|
test-corpus:
|
||||||
@@ -430,19 +303,10 @@ test-corpus-fast:
|
|||||||
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=wasi
|
||||||
|
|
||||||
tinygo-baremetal:
|
|
||||||
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
|
|
||||||
# regression test for #2666: e.g. encoding/hex must pass on baremetal
|
|
||||||
$(TINYGO) test -target cortex-m-qemu encoding/hex
|
|
||||||
|
|
||||||
.PHONY: smoketest
|
.PHONY: smoketest
|
||||||
smoketest:
|
smoketest:
|
||||||
$(TINYGO) version
|
$(TINYGO) version
|
||||||
$(TINYGO) targets > /dev/null
|
|
||||||
# regression test for #2892
|
|
||||||
cd tests/testing/recurse && ($(TINYGO) test ./... > recurse.log && cat recurse.log && test $$(wc -l < recurse.log) = 2 && rm recurse.log)
|
|
||||||
# compile-only platform-independent examples
|
|
||||||
cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test
|
|
||||||
# regression test for #2563
|
# regression test for #2563
|
||||||
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
|
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
|
||||||
# test all examples (except pwm)
|
# test all examples (except pwm)
|
||||||
@@ -460,8 +324,6 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo2
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
|
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
|
||||||
@@ -478,10 +340,6 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
|
||||||
@$(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
|
||||||
@@ -490,14 +348,12 @@ ifneq ($(WASM), 0)
|
|||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
|
||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=microbit examples/microbit-blink
|
$(TINYGO) build -size short -o test.wasm -tags=pca10040 examples/blinky2
|
||||||
|
@$(MD5SUM) test.wasm
|
||||||
|
$(TINYGO) build -size short -o test.wasm -tags=pca10056 examples/blinky2
|
||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
|
||||||
@$(MD5SUM) test.wasm
|
@$(MD5SUM) test.wasm
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
|
||||||
@$(MD5SUM) test.wasm
|
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/serial
|
|
||||||
@$(MD5SUM) test.wasm
|
|
||||||
endif
|
endif
|
||||||
# test all targets/boards
|
# test all targets/boards
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
||||||
@@ -548,8 +404,6 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=matrixportal-m4 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
|
||||||
@@ -588,8 +442,6 @@ endif
|
|||||||
@$(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/serial
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
|
||||||
@@ -616,22 +468,6 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=qtpy-rp2040 examples/echo
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=tufty2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=xiao-rp2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
|
|
||||||
@$(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
|
||||||
@@ -639,13 +475,6 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
# test usb
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
|
||||||
@$(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
|
||||||
@@ -709,19 +538,15 @@ ifneq ($(XTENSA), 0)
|
|||||||
@$(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/serial
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
|
||||||
@$(MD5SUM) test.bin
|
|
||||||
endif
|
endif
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
||||||
@$(MD5SUM) test.bin
|
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
|
|
||||||
@$(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=m5stamp-c3 examples/serial
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/serial
|
|
||||||
@$(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=hifive1-qemu examples/serial
|
||||||
|
@$(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
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
@@ -741,8 +566,6 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
|
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
|
||||||
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
|
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
|
||||||
GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
|
|
||||||
GOOS=darwin GOARCH=arm64 $(TINYGO) build -size short -o test ./testdata/cgo
|
|
||||||
ifneq ($(OS),Windows_NT)
|
ifneq ($(OS),Windows_NT)
|
||||||
# TODO: this does not yet work on Windows. Somehow, unused functions are
|
# TODO: this does not yet work on Windows. Somehow, unused functions are
|
||||||
# not garbage collected.
|
# not garbage collected.
|
||||||
@@ -757,7 +580,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
|
|||||||
@mkdir -p build/release/tinygo/bin
|
@mkdir -p build/release/tinygo/bin
|
||||||
@mkdir -p build/release/tinygo/lib/clang/include
|
@mkdir -p build/release/tinygo/lib/clang/include
|
||||||
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
||||||
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
|
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
|
||||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
|
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
|
||||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
||||||
@mkdir -p build/release/tinygo/lib/musl/arch
|
@mkdir -p build/release/tinygo/lib/musl/arch
|
||||||
@@ -778,7 +601,9 @@ endif
|
|||||||
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
|
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
|
||||||
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
|
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
|
||||||
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
|
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
|
||||||
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
|
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
|
||||||
|
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
|
||||||
|
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
|
||||||
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
|
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
|
||||||
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
|
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
|
||||||
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
|
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
|
||||||
@@ -794,7 +619,6 @@ endif
|
|||||||
@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/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/signal build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
|
||||||
@@ -813,32 +637,23 @@ endif
|
|||||||
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
|
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
|
||||||
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
|
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
|
||||||
@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-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/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/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
|
||||||
@cp -rp src build/release/tinygo/src
|
@cp -rp src build/release/tinygo/src
|
||||||
@cp -rp targets build/release/tinygo/targets
|
@cp -rp targets build/release/tinygo/targets
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
|
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
|
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
|
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
|
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
|
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
|
||||||
./build/release/tinygo/bin/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
|
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
|
||||||
|
|
||||||
release:
|
release: build/release
|
||||||
tar -czf build/release.tar.gz -C build/release tinygo
|
tar -czf build/release.tar.gz -C build/release tinygo
|
||||||
|
|
||||||
DEB_ARCH ?= native
|
deb: build/release
|
||||||
deb:
|
|
||||||
@mkdir -p build/release-deb/usr/local/bin
|
@mkdir -p build/release-deb/usr/local/bin
|
||||||
@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 -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)
|
|
||||||
release: build/release
|
|
||||||
deb: build/release
|
|
||||||
endif
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
|||||||
|
|
||||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||||
|
|
||||||
The following 91 microcontroller boards are currently supported:
|
The following 80 microcontroller boards are currently supported:
|
||||||
|
|
||||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||||
@@ -59,16 +59,13 @@ The following 91 microcontroller boards are currently supported:
|
|||||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||||
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
||||||
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
||||||
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
|
|
||||||
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
|
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
|
||||||
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
|
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
|
||||||
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
|
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
|
||||||
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
|
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
|
||||||
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
||||||
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
||||||
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
|
|
||||||
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||||
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
|
|
||||||
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
||||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||||
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
||||||
@@ -87,17 +84,14 @@ The following 91 microcontroller boards are currently supported:
|
|||||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||||
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
||||||
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
|
|
||||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||||
* [iLabs Challenger RP2040 LoRa](https://ilabs.se/product/challenger-rp2040-lora/)
|
|
||||||
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
||||||
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
||||||
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
||||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||||
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
||||||
* [MCH2022 badge](https://badge.team/docs/badges/mch2022/)
|
|
||||||
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
||||||
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
|
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
|
||||||
* [Nintendo Switch](https://www.nintendo.com/switch/)
|
* [Nintendo Switch](https://www.nintendo.com/switch/)
|
||||||
@@ -109,24 +103,17 @@ The following 91 microcontroller boards are currently supported:
|
|||||||
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
||||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||||
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
|
|
||||||
* [Pimoroni Tufty2040](https://shop.pimoroni.com/products/tufty-2040)
|
|
||||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||||
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
||||||
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
|
|
||||||
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
||||||
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
||||||
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
||||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||||
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
|
|
||||||
* [Seeed XIAO ESP32C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
|
|
||||||
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
|
|
||||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
|
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
|
||||||
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
|
|
||||||
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||||
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ import (
|
|||||||
// makeArchive creates an arcive for static linking from a list of object files
|
// makeArchive creates an arcive for static linking from a list of object files
|
||||||
// given as a parameter. It is equivalent to the following command:
|
// given as a parameter. It is equivalent to the following command:
|
||||||
//
|
//
|
||||||
// ar -rcs <archivePath> <objs...>
|
// ar -rcs <archivePath> <objs...>
|
||||||
func makeArchive(arfile *os.File, objs []string) error {
|
func makeArchive(arfile *os.File, objs []string) error {
|
||||||
// Open the archive file.
|
// Open the archive file.
|
||||||
arwriter := ar.NewWriter(arfile)
|
arwriter := ar.NewWriter(arfile)
|
||||||
|
|||||||
+119
-341
@@ -4,7 +4,6 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@@ -14,7 +13,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/types"
|
"go/types"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io/fs"
|
"io/ioutil"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -38,14 +37,8 @@ import (
|
|||||||
// BuildResult is the output of a build. This includes the binary itself and
|
// BuildResult is the output of a build. This includes the binary itself and
|
||||||
// some other metadata that is obtained while building the binary.
|
// some other metadata that is obtained while building the binary.
|
||||||
type BuildResult struct {
|
type BuildResult struct {
|
||||||
// The executable directly from the linker, usually including debug
|
|
||||||
// information. Used for GDB for example.
|
|
||||||
Executable string
|
|
||||||
|
|
||||||
// A path to the output binary. It will be removed after Build returns, so
|
// A path to the output binary. It will be removed after Build returns, so
|
||||||
// if it should be kept it must be copied or moved away.
|
// if it should be kept it must be copied or moved away.
|
||||||
// It is often the same as Executable, but differs if the output format is
|
|
||||||
// .hex for example (instead of the usual ELF).
|
|
||||||
Binary string
|
Binary string
|
||||||
|
|
||||||
// The directory of the main package. This is useful for testing as the test
|
// The directory of the main package. This is useful for testing as the test
|
||||||
@@ -81,7 +74,6 @@ type packageAction struct {
|
|||||||
Config *compiler.Config
|
Config *compiler.Config
|
||||||
CFlags []string
|
CFlags []string
|
||||||
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
|
|
||||||
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 int // LLVM optimization level (0-3)
|
||||||
SizeLevel int // LLVM optimization for size level (0-2)
|
SizeLevel int // LLVM optimization for size level (0-2)
|
||||||
@@ -103,24 +95,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a temporary directory for intermediary files.
|
// Create a temporary directory for intermediary files.
|
||||||
dir, err := os.MkdirTemp("", "tinygo")
|
dir, err := ioutil.TempDir("", "tinygo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if config.Options.Work {
|
defer os.RemoveAll(dir)
|
||||||
fmt.Printf("WORK=%s\n", dir)
|
|
||||||
} else {
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the build cache directory, which is used to speed up incremental
|
|
||||||
// builds.
|
|
||||||
cacheDir := goenv.Get("GOCACHE")
|
|
||||||
if cacheDir == "off" {
|
|
||||||
// Use temporary build directory instead, effectively disabling the
|
|
||||||
// build cache.
|
|
||||||
cacheDir = dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
@@ -128,9 +107,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
var libcDependencies []*compileJob
|
var libcDependencies []*compileJob
|
||||||
switch config.Target.Libc {
|
switch config.Target.Libc {
|
||||||
case "darwin-libSystem":
|
|
||||||
job := makeDarwinLibSystemJob(config, dir)
|
|
||||||
libcDependencies = append(libcDependencies, job)
|
|
||||||
case "musl":
|
case "musl":
|
||||||
job, unlock, err := Musl.load(config, dir)
|
job, unlock, err := Musl.load(config, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -148,7 +124,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
libcDependencies = append(libcDependencies, libcJob)
|
libcDependencies = append(libcDependencies, libcJob)
|
||||||
case "wasi-libc":
|
case "wasi-libc":
|
||||||
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
|
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
|
||||||
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
return 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))
|
||||||
@@ -178,7 +154,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
|
|
||||||
Scheduler: config.Scheduler(),
|
Scheduler: config.Scheduler(),
|
||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.StackSize(),
|
DefaultStackSize: config.Target.DefaultStackSize,
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: true,
|
Debug: true,
|
||||||
}
|
}
|
||||||
@@ -190,10 +166,9 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
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, []string{pkgName}, config.ClangHeaders, types.Config{
|
||||||
Sizes: compiler.Sizes(machine),
|
Sizes: compiler.Sizes(machine),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -211,23 +186,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// Add jobs to compile each package.
|
// Add jobs to compile each package.
|
||||||
// Packages that have a cache hit will not be compiled again.
|
// Packages that have a cache hit will not be compiled again.
|
||||||
var packageJobs []*compileJob
|
var packageJobs []*compileJob
|
||||||
packageActionIDJobs := make(map[string]*compileJob)
|
packageBitcodePaths := make(map[string]string)
|
||||||
|
packageActionIDs := make(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 == nil {
|
|
||||||
config.Options.GlobalValues = make(map[string]map[string]string)
|
|
||||||
}
|
|
||||||
if config.Options.GlobalValues["runtime"] == nil {
|
|
||||||
config.Options.GlobalValues["runtime"] = make(map[string]string)
|
|
||||||
}
|
|
||||||
config.Options.GlobalValues["runtime"]["buildVersion"] = version
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -237,114 +197,58 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
}
|
}
|
||||||
sort.Strings(undefinedGlobals)
|
sort.Strings(undefinedGlobals)
|
||||||
|
|
||||||
// Make compile jobs to load files to be embedded in the output binary.
|
// Create a cache key: a hash from the action ID below that contains all
|
||||||
var actionIDDependencies []*compileJob
|
// the parameters for the build.
|
||||||
allFiles := map[string][]*loader.EmbedFile{}
|
actionID := packageAction{
|
||||||
for _, files := range pkg.EmbedGlobals {
|
ImportPath: pkg.ImportPath,
|
||||||
for _, file := range files {
|
CompilerBuildID: string(compilerBuildID),
|
||||||
allFiles[file.Name] = append(allFiles[file.Name], file)
|
TinyGoVersion: goenv.Version,
|
||||||
}
|
LLVMVersion: llvm.Version,
|
||||||
|
Config: compilerConfig,
|
||||||
|
CFlags: pkg.CFlags,
|
||||||
|
FileHashes: make(map[string]string, len(pkg.FileHashes)),
|
||||||
|
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
|
||||||
|
OptLevel: optLevel,
|
||||||
|
SizeLevel: sizeLevel,
|
||||||
|
UndefinedGlobals: undefinedGlobals,
|
||||||
}
|
}
|
||||||
for name, files := range allFiles {
|
for filePath, hash := range pkg.FileHashes {
|
||||||
name := name
|
actionID.FileHashes[filePath] = hex.EncodeToString(hash)
|
||||||
files := files
|
|
||||||
job := &compileJob{
|
|
||||||
description: "make object file for " + name,
|
|
||||||
run: func(job *compileJob) error {
|
|
||||||
// Read the file contents in memory.
|
|
||||||
path := filepath.Join(pkg.Dir, name)
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash the file.
|
|
||||||
sum := sha256.Sum256(data)
|
|
||||||
hexSum := hex.EncodeToString(sum[:16])
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
file.Size = uint64(len(data))
|
|
||||||
file.Hash = hexSum
|
|
||||||
if file.NeedsData {
|
|
||||||
file.Data = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
job.result, err = createEmbedObjectFile(string(data), hexSum, name, pkg.OriginalDir(), dir, compilerConfig)
|
|
||||||
return err
|
|
||||||
},
|
|
||||||
}
|
|
||||||
actionIDDependencies = append(actionIDDependencies, job)
|
|
||||||
embedFileObjects = append(embedFileObjects, job)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action ID jobs need to know the action ID of all the jobs the package
|
|
||||||
// imports.
|
|
||||||
var importedPackages []*compileJob
|
|
||||||
for _, imported := range pkg.Pkg.Imports() {
|
for _, imported := range pkg.Pkg.Imports() {
|
||||||
job, ok := packageActionIDJobs[imported.Path()]
|
hash, ok := packageActionIDs[imported.Path()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("package %s imports %s but couldn't find dependency", pkg.ImportPath, imported.Path())
|
return fmt.Errorf("package %s imports %s but couldn't find dependency", pkg.ImportPath, imported.Path())
|
||||||
}
|
}
|
||||||
importedPackages = append(importedPackages, job)
|
actionID.Imports[imported.Path()] = hash
|
||||||
actionIDDependencies = append(actionIDDependencies, job)
|
|
||||||
}
|
}
|
||||||
|
buf, err := json.Marshal(actionID)
|
||||||
// Create a job that will calculate the action ID for a package compile
|
if err != nil {
|
||||||
// job. The action ID is the cache key that is used for caching this
|
panic(err) // shouldn't happen
|
||||||
// package.
|
|
||||||
packageActionIDJob := &compileJob{
|
|
||||||
description: "calculate cache key for package " + pkg.ImportPath,
|
|
||||||
dependencies: actionIDDependencies,
|
|
||||||
run: func(job *compileJob) error {
|
|
||||||
// Create a cache key: a hash from the action ID below that contains all
|
|
||||||
// the parameters for the build.
|
|
||||||
actionID := packageAction{
|
|
||||||
ImportPath: pkg.ImportPath,
|
|
||||||
CompilerBuildID: string(compilerBuildID),
|
|
||||||
TinyGoVersion: goenv.Version,
|
|
||||||
LLVMVersion: llvm.Version,
|
|
||||||
Config: compilerConfig,
|
|
||||||
CFlags: pkg.CFlags,
|
|
||||||
FileHashes: make(map[string]string, len(pkg.FileHashes)),
|
|
||||||
EmbeddedFiles: make(map[string]string, len(allFiles)),
|
|
||||||
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
|
|
||||||
OptLevel: optLevel,
|
|
||||||
SizeLevel: sizeLevel,
|
|
||||||
UndefinedGlobals: undefinedGlobals,
|
|
||||||
}
|
|
||||||
for filePath, hash := range pkg.FileHashes {
|
|
||||||
actionID.FileHashes[filePath] = hex.EncodeToString(hash)
|
|
||||||
}
|
|
||||||
for name, files := range allFiles {
|
|
||||||
actionID.EmbeddedFiles[name] = files[0].Hash
|
|
||||||
}
|
|
||||||
for i, imported := range pkg.Pkg.Imports() {
|
|
||||||
actionID.Imports[imported.Path()] = importedPackages[i].result
|
|
||||||
}
|
|
||||||
buf, err := json.Marshal(actionID)
|
|
||||||
if err != nil {
|
|
||||||
return err // shouldn't happen
|
|
||||||
}
|
|
||||||
hash := sha512.Sum512_224(buf)
|
|
||||||
job.result = hex.EncodeToString(hash[:])
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
packageActionIDJobs[pkg.ImportPath] = packageActionIDJob
|
hash := sha512.Sum512_224(buf)
|
||||||
|
packageActionIDs[pkg.ImportPath] = hex.EncodeToString(hash[:])
|
||||||
|
|
||||||
// Now create the job to actually build the package. It will exit early
|
// Determine the path of the bitcode file (which is a serialized version
|
||||||
// if the package is already compiled.
|
// of a LLVM module).
|
||||||
|
cacheDir := goenv.Get("GOCACHE")
|
||||||
|
if cacheDir == "off" {
|
||||||
|
// Use temporary build directory instead, effectively disabling the
|
||||||
|
// build cache.
|
||||||
|
cacheDir = dir
|
||||||
|
}
|
||||||
|
bitcodePath := filepath.Join(cacheDir, "pkg-"+hex.EncodeToString(hash[:])+".bc")
|
||||||
|
packageBitcodePaths[pkg.ImportPath] = bitcodePath
|
||||||
|
|
||||||
|
// The package has not yet been compiled, so create a job to do so.
|
||||||
job := &compileJob{
|
job := &compileJob{
|
||||||
description: "compile package " + pkg.ImportPath,
|
description: "compile package " + pkg.ImportPath,
|
||||||
dependencies: []*compileJob{packageActionIDJob},
|
run: func(*compileJob) error {
|
||||||
run: func(job *compileJob) error {
|
|
||||||
job.result = filepath.Join(cacheDir, "pkg-"+packageActionIDJob.result+".bc")
|
|
||||||
// Acquire a lock (if supported).
|
// Acquire a lock (if supported).
|
||||||
unlock := lock(job.result + ".lock")
|
unlock := lock(bitcodePath + ".lock")
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
if _, err := os.Stat(job.result); err == nil {
|
if _, err := os.Stat(bitcodePath); err == nil {
|
||||||
// Already cached, don't recreate this package.
|
// Already cached, don't recreate this package.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -352,8 +256,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// Compile AST to IR. The compiler.CompilePackage function will
|
// Compile AST to IR. The compiler.CompilePackage function will
|
||||||
// build the SSA as needed.
|
// build the SSA as needed.
|
||||||
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
|
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
|
||||||
defer mod.Context().Dispose()
|
|
||||||
defer mod.Dispose()
|
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
@@ -370,7 +272,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// Packages are compiled independently anyway.
|
// Packages are compiled independently anyway.
|
||||||
for _, cgoHeader := range pkg.CGoHeaders {
|
for _, cgoHeader := range pkg.CGoHeaders {
|
||||||
// Store the header text in a temporary file.
|
// Store the header text in a temporary file.
|
||||||
f, err := os.CreateTemp(dir, "cgosnippet-*.c")
|
f, err := ioutil.TempFile(dir, "cgosnippet-*.c")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -431,7 +333,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if pkgInit.IsNil() {
|
if pkgInit.IsNil() {
|
||||||
panic("init not found for " + pkg.Pkg.Path())
|
panic("init not found for " + pkg.Pkg.Path())
|
||||||
}
|
}
|
||||||
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
|
err := interp.RunFunc(pkgInit, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -439,13 +341,33 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
return errors.New("verification error after interpreting " + pkgInit.Name())
|
return errors.New("verification error after interpreting " + pkgInit.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.OptimizePackage(mod, config)
|
// Run function passes for each function in the module.
|
||||||
|
// These passes are intended to be run on each function right
|
||||||
|
// after they're created to reduce IR size (and maybe also for
|
||||||
|
// cache locality to improve performance), but for now they're
|
||||||
|
// run here for each function in turn. Maybe this can be
|
||||||
|
// improved in the future.
|
||||||
|
builder := llvm.NewPassManagerBuilder()
|
||||||
|
defer builder.Dispose()
|
||||||
|
builder.SetOptLevel(optLevel)
|
||||||
|
builder.SetSizeLevel(sizeLevel)
|
||||||
|
funcPasses := llvm.NewFunctionPassManagerForModule(mod)
|
||||||
|
defer funcPasses.Dispose()
|
||||||
|
builder.PopulateFunc(funcPasses)
|
||||||
|
funcPasses.InitializeFunc()
|
||||||
|
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
||||||
|
if fn.IsDeclaration() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
funcPasses.RunFunc(fn)
|
||||||
|
}
|
||||||
|
funcPasses.FinalizeFunc()
|
||||||
|
|
||||||
// Serialize the LLVM module as a bitcode file.
|
// Serialize the LLVM module as a bitcode file.
|
||||||
// Write to a temporary path that is renamed to the destination
|
// Write to a temporary path that is renamed to the destination
|
||||||
// file to avoid race conditions with other TinyGo invocatiosn
|
// file to avoid race conditions with other TinyGo invocatiosn
|
||||||
// that might also be compiling this package at the same time.
|
// that might also be compiling this package at the same time.
|
||||||
f, err := os.CreateTemp(filepath.Dir(job.result), filepath.Base(job.result))
|
f, err := ioutil.TempFile(filepath.Dir(bitcodePath), filepath.Base(bitcodePath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -465,13 +387,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// WriteBitcodeToFile doesn't produce a useful error on its
|
// WriteBitcodeToFile doesn't produce a useful error on its
|
||||||
// own, so create a somewhat useful error message here.
|
// own, so create a somewhat useful error message here.
|
||||||
return fmt.Errorf("failed to write bitcode for package %s to file %s", pkg.ImportPath, job.result)
|
return fmt.Errorf("failed to write bitcode for package %s to file %s", pkg.ImportPath, bitcodePath)
|
||||||
}
|
}
|
||||||
err = f.Close()
|
err = f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(f.Name(), job.result)
|
return os.Rename(f.Name(), bitcodePath)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
packageJobs = append(packageJobs, job)
|
packageJobs = append(packageJobs, job)
|
||||||
@@ -479,13 +401,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
|
|
||||||
// Add job that links and optimizes all packages together.
|
// Add job that links and optimizes all packages together.
|
||||||
var mod llvm.Module
|
var mod llvm.Module
|
||||||
defer func() {
|
|
||||||
if !mod.IsNil() {
|
|
||||||
ctx := mod.Context()
|
|
||||||
mod.Dispose()
|
|
||||||
ctx.Dispose()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
var stackSizeLoads []string
|
var stackSizeLoads []string
|
||||||
programJob := &compileJob{
|
programJob := &compileJob{
|
||||||
description: "link+optimize packages (LTO)",
|
description: "link+optimize packages (LTO)",
|
||||||
@@ -494,9 +409,9 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// Load and link all the bitcode files. This does not yet optimize
|
// Load and link all the bitcode files. This does not yet optimize
|
||||||
// anything, it only links the bitcode files together.
|
// anything, it only links the bitcode files together.
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
mod = ctx.NewModule("main")
|
mod = ctx.NewModule("")
|
||||||
for _, pkgJob := range packageJobs {
|
for _, pkg := range lprogram.Sorted() {
|
||||||
pkgMod, err := ctx.ParseBitcodeFile(pkgJob.result)
|
pkgMod, err := ctx.ParseBitcodeFile(packageBitcodePaths[pkg.ImportPath])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to load bitcode file: %w", err)
|
return fmt.Errorf("failed to load bitcode file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -588,20 +503,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer llvmBuf.Dispose()
|
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
||||||
return os.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
|
||||||
case ".bc":
|
case ".bc":
|
||||||
var buf llvm.MemoryBuffer
|
data := llvm.WriteBitcodeToMemoryBuffer(mod).Bytes()
|
||||||
if config.UseThinLTO() {
|
return ioutil.WriteFile(outpath, data, 0666)
|
||||||
buf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
|
|
||||||
} else {
|
|
||||||
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
|
|
||||||
}
|
|
||||||
defer buf.Dispose()
|
|
||||||
return os.WriteFile(outpath, buf.Bytes(), 0666)
|
|
||||||
case ".ll":
|
case ".ll":
|
||||||
data := []byte(mod.String())
|
data := []byte(mod.String())
|
||||||
return os.WriteFile(outpath, data, 0666)
|
return ioutil.WriteFile(outpath, data, 0666)
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
@@ -618,18 +526,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
dependencies: []*compileJob{programJob},
|
dependencies: []*compileJob{programJob},
|
||||||
result: objfile,
|
result: objfile,
|
||||||
run: func(*compileJob) error {
|
run: func(*compileJob) error {
|
||||||
var llvmBuf llvm.MemoryBuffer
|
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
||||||
if config.UseThinLTO() {
|
if err != nil {
|
||||||
llvmBuf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
|
return err
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
llvmBuf, err = machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
defer llvmBuf.Dispose()
|
return ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666)
|
||||||
return os.WriteFile(objfile, llvmBuf.Bytes(), 0666)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +562,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
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, dir, config.CFlags(), config.UseThinLTO(), config.Options.PrintCommands)
|
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.Options.PrintCommands)
|
||||||
job.result = result
|
job.result = result
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
@@ -679,7 +580,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
job := &compileJob{
|
job := &compileJob{
|
||||||
description: "compile CGo file " + abspath,
|
description: "compile CGo file " + abspath,
|
||||||
run: func(job *compileJob) error {
|
run: func(job *compileJob) error {
|
||||||
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.UseThinLTO(), config.Options.PrintCommands)
|
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.Options.PrintCommands)
|
||||||
job.result = result
|
job.result = result
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
@@ -697,9 +598,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// Add libc dependencies, if they exist.
|
// Add libc dependencies, if they exist.
|
||||||
linkerDependencies = append(linkerDependencies, libcDependencies...)
|
linkerDependencies = append(linkerDependencies, libcDependencies...)
|
||||||
|
|
||||||
// Add embedded files.
|
|
||||||
linkerDependencies = append(linkerDependencies, embedFileObjects...)
|
|
||||||
|
|
||||||
// Strip debug information with -no-debug.
|
// Strip debug information with -no-debug.
|
||||||
if !config.Debug() {
|
if !config.Debug() {
|
||||||
for _, tag := range config.BuildTags() {
|
for _, tag := range config.BuildTags() {
|
||||||
@@ -709,12 +607,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
return fmt.Errorf("stripping debug information is unnecessary for baremetal targets")
|
return fmt.Errorf("stripping debug information is unnecessary for baremetal targets")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.GOOS() == "darwin" {
|
|
||||||
// Debug information isn't stored in the binary itself on MacOS but
|
|
||||||
// is left in the object files by default. The binary does store the
|
|
||||||
// path to these object files though.
|
|
||||||
return errors.New("cannot remove debug information: MacOS doesn't store debug info in the executable by default")
|
|
||||||
}
|
|
||||||
if config.Target.Linker == "wasm-ld" {
|
if config.Target.Linker == "wasm-ld" {
|
||||||
// Don't just strip debug information, also compress relocations
|
// Don't just strip debug information, also compress relocations
|
||||||
// while we're at it. Relocations can only be compressed when debug
|
// while we're at it. Relocations can only be compressed when debug
|
||||||
@@ -724,8 +616,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
// ld.lld is also used on Linux.
|
// ld.lld is also used on Linux.
|
||||||
ldflags = append(ldflags, "--strip-debug")
|
ldflags = append(ldflags, "--strip-debug")
|
||||||
} else {
|
} else {
|
||||||
// Other linkers may have different flags.
|
switch config.GOOS() {
|
||||||
return errors.New("cannot remove debug information: unknown linker: " + config.Target.Linker)
|
case "linux":
|
||||||
|
// Either real linux or an embedded system (like AVR) that
|
||||||
|
// pretends to be Linux. It's a ELF linker wrapped by GCC in any
|
||||||
|
// case (not ld.lld - that case is handled above).
|
||||||
|
ldflags = append(ldflags, "-Wl,--strip-debug")
|
||||||
|
case "darwin":
|
||||||
|
// MacOS (darwin) doesn't have a linker flag to strip debug
|
||||||
|
// information. Apple expects you to use the strip command
|
||||||
|
// instead.
|
||||||
|
return errors.New("cannot remove debug information: MacOS doesn't suppor this linker flag")
|
||||||
|
default:
|
||||||
|
// Other OSes may have different flags.
|
||||||
|
return errors.New("cannot remove debug information: unknown OS: " + config.GOOS())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,37 +649,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if config.Options.PrintCommands != nil {
|
if config.Options.PrintCommands != nil {
|
||||||
config.Options.PrintCommands(config.Target.Linker, ldflags...)
|
config.Options.PrintCommands(config.Target.Linker, ldflags...)
|
||||||
}
|
}
|
||||||
if config.UseThinLTO() {
|
|
||||||
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
|
|
||||||
if config.GOOS() == "windows" {
|
|
||||||
// Options for the MinGW wrapper for the lld COFF linker.
|
|
||||||
ldflags = append(ldflags,
|
|
||||||
"-Xlink=/opt:lldlto="+strconv.Itoa(optLevel),
|
|
||||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
|
|
||||||
} else if config.GOOS() == "darwin" {
|
|
||||||
// Options for the ld64-compatible lld linker.
|
|
||||||
ldflags = append(ldflags,
|
|
||||||
"--lto-O"+strconv.Itoa(optLevel),
|
|
||||||
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
|
|
||||||
} else {
|
|
||||||
// Options for the ELF linker.
|
|
||||||
ldflags = append(ldflags,
|
|
||||||
"--lto-O"+strconv.Itoa(optLevel),
|
|
||||||
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if config.CodeModel() != "default" {
|
|
||||||
ldflags = append(ldflags,
|
|
||||||
"-mllvm", "-code-model="+config.CodeModel())
|
|
||||||
}
|
|
||||||
if sizeLevel >= 2 {
|
|
||||||
// Workaround with roughly the same effect as
|
|
||||||
// https://reviews.llvm.org/D119342.
|
|
||||||
// Can hopefully be removed in LLVM 15.
|
|
||||||
ldflags = append(ldflags,
|
|
||||||
"-mllvm", "--rotation-max-header-size=0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = link(config.Target.Linker, ldflags...)
|
err = link(config.Target.Linker, ldflags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &commandError{"failed to link", executable, err}
|
return &commandError{"failed to link", executable, err}
|
||||||
@@ -905,7 +779,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "esp32", "esp32-img", "esp32c3", "esp8266":
|
case "esp32", "esp32c3", "esp8266":
|
||||||
// Special format for the ESP family of chips (parsed by the ROM
|
// Special format for the ESP family of chips (parsed by the ROM
|
||||||
// bootloader).
|
// bootloader).
|
||||||
tmppath = filepath.Join(dir, "main"+outext)
|
tmppath = filepath.Join(dir, "main"+outext)
|
||||||
@@ -937,7 +811,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
}
|
}
|
||||||
|
|
||||||
return action(BuildResult{
|
return action(BuildResult{
|
||||||
Executable: executable,
|
|
||||||
Binary: tmppath,
|
Binary: tmppath,
|
||||||
MainDir: lprogram.MainPkg().Dir,
|
MainDir: lprogram.MainPkg().Dir,
|
||||||
ModuleRoot: moduleroot,
|
ModuleRoot: moduleroot,
|
||||||
@@ -945,117 +818,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// createEmbedObjectFile creates a new object file with the given contents, for
|
|
||||||
// the embed package.
|
|
||||||
func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, compilerConfig *compiler.Config) (string, error) {
|
|
||||||
// TODO: this works for small files, but can be a problem for larger files.
|
|
||||||
// For larger files, it seems more appropriate to generate the object file
|
|
||||||
// manually without going through LLVM.
|
|
||||||
// On the other hand, generating DWARF like we do here can be difficult
|
|
||||||
// without assistance from LLVM.
|
|
||||||
|
|
||||||
// Create new LLVM module just for this file.
|
|
||||||
ctx := llvm.NewContext()
|
|
||||||
defer ctx.Dispose()
|
|
||||||
mod := ctx.NewModule("data")
|
|
||||||
defer mod.Dispose()
|
|
||||||
|
|
||||||
// Create data global.
|
|
||||||
value := ctx.ConstString(data, false)
|
|
||||||
globalName := "embed/file_" + hexSum
|
|
||||||
global := llvm.AddGlobal(mod, value.Type(), globalName)
|
|
||||||
global.SetInitializer(value)
|
|
||||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
|
||||||
global.SetGlobalConstant(true)
|
|
||||||
global.SetUnnamedAddr(true)
|
|
||||||
global.SetAlignment(1)
|
|
||||||
if compilerConfig.GOOS != "darwin" {
|
|
||||||
// MachO doesn't support COMDATs, while COFF requires it (to avoid
|
|
||||||
// "duplicate symbol" errors). ELF works either way.
|
|
||||||
// Therefore, only use a COMDAT on non-MachO systems (aka non-MacOS).
|
|
||||||
global.SetComdat(mod.Comdat(globalName))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add DWARF debug information to this global, so that it is
|
|
||||||
// correctly counted when compiling with the -size= flag.
|
|
||||||
dibuilder := llvm.NewDIBuilder(mod)
|
|
||||||
dibuilder.CreateCompileUnit(llvm.DICompileUnit{
|
|
||||||
Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?)
|
|
||||||
File: sourceFile,
|
|
||||||
Dir: sourceDir,
|
|
||||||
Producer: "TinyGo",
|
|
||||||
Optimized: false,
|
|
||||||
})
|
|
||||||
ditype := dibuilder.CreateArrayType(llvm.DIArrayType{
|
|
||||||
SizeInBits: uint64(len(data)) * 8,
|
|
||||||
AlignInBits: 8,
|
|
||||||
ElementType: dibuilder.CreateBasicType(llvm.DIBasicType{
|
|
||||||
Name: "byte",
|
|
||||||
SizeInBits: 8,
|
|
||||||
Encoding: llvm.DW_ATE_unsigned_char,
|
|
||||||
}),
|
|
||||||
Subscripts: []llvm.DISubrange{
|
|
||||||
{
|
|
||||||
Lo: 0,
|
|
||||||
Count: int64(len(data)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
difile := dibuilder.CreateFile(sourceFile, sourceDir)
|
|
||||||
diglobalexpr := dibuilder.CreateGlobalVariableExpression(difile, llvm.DIGlobalVariableExpression{
|
|
||||||
Name: globalName,
|
|
||||||
File: difile,
|
|
||||||
Line: 1,
|
|
||||||
Type: ditype,
|
|
||||||
Expr: dibuilder.CreateExpression(nil),
|
|
||||||
AlignInBits: 8,
|
|
||||||
})
|
|
||||||
global.AddMetadata(0, diglobalexpr)
|
|
||||||
mod.AddNamedMetadataOperand("llvm.module.flags",
|
|
||||||
ctx.MDNode([]llvm.Metadata{
|
|
||||||
llvm.ConstInt(ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch
|
|
||||||
ctx.MDString("Debug Info Version"),
|
|
||||||
llvm.ConstInt(ctx.Int32Type(), 3, false).ConstantAsMetadata(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
mod.AddNamedMetadataOperand("llvm.module.flags",
|
|
||||||
ctx.MDNode([]llvm.Metadata{
|
|
||||||
llvm.ConstInt(ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch
|
|
||||||
ctx.MDString("Dwarf Version"),
|
|
||||||
llvm.ConstInt(ctx.Int32Type(), 4, false).ConstantAsMetadata(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
dibuilder.Finalize()
|
|
||||||
dibuilder.Destroy()
|
|
||||||
|
|
||||||
// Write this LLVM module out as an object file.
|
|
||||||
machine, err := compiler.NewTargetMachine(compilerConfig)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer machine.Dispose()
|
|
||||||
outfile, err := os.CreateTemp(tmpdir, "embed-"+hexSum+"-*.o")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer outfile.Close()
|
|
||||||
buf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer buf.Dispose()
|
|
||||||
_, err = outfile.Write(buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return outfile.Name(), outfile.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) error {
|
||||||
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
|
err := interp.Run(mod, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1072,7 +839,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.GOOS() != "darwin" && !config.UseThinLTO() {
|
if config.GOOS() != "darwin" {
|
||||||
transform.ApplyFunctionSections(mod) // -ffunction-sections
|
transform.ApplyFunctionSections(mod) // -ffunction-sections
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1105,6 +872,17 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
|||||||
return errors.New("verification failure after LLVM optimization passes")
|
return errors.New("verification failure after LLVM optimization passes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LLVM 11 by default tries to emit tail calls (even with the target feature
|
||||||
|
// disabled) unless it is explicitly disabled with a function attribute.
|
||||||
|
// This is a problem, as it tries to emit them and prints an error when it
|
||||||
|
// can't with this feature disabled.
|
||||||
|
// Because as of september 2020 tail calls are not yet widely supported,
|
||||||
|
// they need to be disabled until they are widely supported (at which point
|
||||||
|
// the +tail-call target feautre can be set).
|
||||||
|
if strings.HasPrefix(config.Triple(), "wasm") {
|
||||||
|
transform.DisableTailCalls(mod)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1367,10 +1145,10 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
|
|||||||
//
|
//
|
||||||
// It might print something like the following:
|
// It might print something like the following:
|
||||||
//
|
//
|
||||||
// function stack usage (in bytes)
|
// function stack usage (in bytes)
|
||||||
// Reset_Handler 316
|
// Reset_Handler 316
|
||||||
// examples/blinky2.led1 92
|
// examples/blinky2.led1 92
|
||||||
// runtime.run$1 300
|
// runtime.run$1 300
|
||||||
func printStacks(calculatedStacks []string, stackSizes map[string]functionStackSize) {
|
func printStacks(calculatedStacks []string, stackSizes map[string]functionStackSize) {
|
||||||
// Print the sizes of all stacks.
|
// Print the sizes of all stacks.
|
||||||
fmt.Printf("%-32s %s\n", "function", "stack usage (in bytes)")
|
fmt.Printf("%-32s %s\n", "function", "stack usage (in bytes)")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package builder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -25,7 +26,7 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
"cortex-m0",
|
"cortex-m0",
|
||||||
"cortex-m0plus",
|
"cortex-m0plus",
|
||||||
"cortex-m3",
|
"cortex-m3",
|
||||||
"cortex-m33",
|
//"cortex-m33", // TODO: broken in LLVM 11, fixed in https://reviews.llvm.org/D90305
|
||||||
"cortex-m4",
|
"cortex-m4",
|
||||||
"cortex-m7",
|
"cortex-m7",
|
||||||
"esp32c3",
|
"esp32c3",
|
||||||
@@ -89,7 +90,7 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
|
|||||||
|
|
||||||
// Create a very simple C input file.
|
// Create a very simple C input file.
|
||||||
srcpath := filepath.Join(testDir, "test.c")
|
srcpath := filepath.Join(testDir, "test.c")
|
||||||
err = os.WriteFile(srcpath, []byte("int add(int a, int b) { return a + b; }"), 0o666)
|
err = ioutil.WriteFile(srcpath, []byte("int add(int a, int b) { return a + b; }"), 0o666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not write target file %s: %s", srcpath, err)
|
t.Fatalf("could not write target file %s: %s", srcpath, err)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ func ReadBuildID() ([]byte, error) {
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "linux", "freebsd", "android":
|
case "linux", "freebsd":
|
||||||
// Read the GNU build id section. (Not sure about FreeBSD though...)
|
// Read the GNU build id section. (Not sure about FreeBSD though...)
|
||||||
file, err := elf.NewFile(f)
|
file, err := elf.NewFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+3
-22
@@ -1,11 +1,7 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
||||||
@@ -40,6 +36,7 @@ var genericBuiltins = []string{
|
|||||||
"divdf3.c",
|
"divdf3.c",
|
||||||
"divdi3.c",
|
"divdi3.c",
|
||||||
"divmoddi4.c",
|
"divmoddi4.c",
|
||||||
|
"divmodsi4.c",
|
||||||
"divsc3.c",
|
"divsc3.c",
|
||||||
"divsf3.c",
|
"divsf3.c",
|
||||||
"divsi3.c",
|
"divsi3.c",
|
||||||
@@ -75,7 +72,6 @@ var genericBuiltins = []string{
|
|||||||
"floatunsisf.c",
|
"floatunsisf.c",
|
||||||
"floatuntidf.c",
|
"floatuntidf.c",
|
||||||
"floatuntisf.c",
|
"floatuntisf.c",
|
||||||
"fp_mode.c",
|
|
||||||
//"int_util.c",
|
//"int_util.c",
|
||||||
"lshrdi3.c",
|
"lshrdi3.c",
|
||||||
"lshrti3.c",
|
"lshrti3.c",
|
||||||
@@ -126,6 +122,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",
|
||||||
@@ -152,14 +149,6 @@ var aeabiBuiltins = []string{
|
|||||||
"arm/aeabi_memset.S",
|
"arm/aeabi_memset.S",
|
||||||
"arm/aeabi_uidivmod.S",
|
"arm/aeabi_uidivmod.S",
|
||||||
"arm/aeabi_uldivmod.S",
|
"arm/aeabi_uldivmod.S",
|
||||||
|
|
||||||
// These two are not technically EABI builtins but are used by them and only
|
|
||||||
// seem to be used on ARM. LLVM seems to use __divsi3 and __modsi3 on most
|
|
||||||
// other architectures.
|
|
||||||
// Most importantly, they have a different calling convention on AVR so
|
|
||||||
// should not be used on AVR.
|
|
||||||
"divmodsi4.c",
|
|
||||||
"udivmodsi4.c",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompilerRT is a library with symbols required by programs compiled with LLVM.
|
// CompilerRT is a library with symbols required by programs compiled with LLVM.
|
||||||
@@ -172,15 +161,7 @@ var CompilerRT = Library{
|
|||||||
cflags: func(target, headerPath string) []string {
|
cflags: func(target, headerPath string) []string {
|
||||||
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
|
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
|
||||||
},
|
},
|
||||||
sourceDir: func() string {
|
sourceDir: "lib/compiler-rt/lib/builtins",
|
||||||
llvmDir := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project/compiler-rt/lib/builtins")
|
|
||||||
if _, err := os.Stat(llvmDir); err == nil {
|
|
||||||
// Release build.
|
|
||||||
return llvmDir
|
|
||||||
}
|
|
||||||
// Development build.
|
|
||||||
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
|
|
||||||
},
|
|
||||||
librarySources: func(target string) []string {
|
librarySources: func(target string) []string {
|
||||||
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
||||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||||
|
|||||||
+41
-50
@@ -10,7 +10,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -33,30 +33,30 @@ import (
|
|||||||
// Because of this complexity, every file has in fact two cached build outputs:
|
// Because of this complexity, every file has in fact two cached build outputs:
|
||||||
// the file itself, and the list of dependencies. Its operation is as follows:
|
// the file itself, and the list of dependencies. Its operation is as follows:
|
||||||
//
|
//
|
||||||
// depfile = hash(path, compiler, cflags, ...)
|
// depfile = hash(path, compiler, cflags, ...)
|
||||||
// if depfile exists:
|
// if depfile exists:
|
||||||
// outfile = hash of all files and depfile name
|
// outfile = hash of all files and depfile name
|
||||||
// if outfile exists:
|
// if outfile exists:
|
||||||
// # cache hit
|
// # cache hit
|
||||||
// return outfile
|
// return outfile
|
||||||
// # cache miss
|
// # cache miss
|
||||||
// tmpfile = compile file
|
// tmpfile = compile file
|
||||||
// read dependencies (side effect of compile)
|
// read dependencies (side effect of compile)
|
||||||
// write depfile
|
// write depfile
|
||||||
// outfile = hash of all files and depfile name
|
// outfile = hash of all files and depfile name
|
||||||
// rename tmpfile to outfile
|
// rename tmpfile to outfile
|
||||||
//
|
//
|
||||||
// There are a few edge cases that are not handled:
|
// There are a few edge cases that are not handled:
|
||||||
// - If a file is added to an include path, that file may be included instead of
|
// - If a file is added to an include path, that file may be included instead of
|
||||||
// some other file. This would be fixed by also including lookup failures in the
|
// some other file. This would be fixed by also including lookup failures in the
|
||||||
// dependencies file, but I'm not aware of a compiler which does that.
|
// dependencies file, but I'm not aware of a compiler which does that.
|
||||||
// - The Makefile syntax that compilers output has issues, see readDepFile for
|
// - The Makefile syntax that compilers output has issues, see readDepFile for
|
||||||
// details.
|
// details.
|
||||||
// - A header file may be changed to add/remove an include. This invalidates the
|
// - A header file may be changed to add/remove an include. This invalidates the
|
||||||
// depfile but without invalidating its name. For this reason, the depfile is
|
// depfile but without invalidating its name. For this reason, the depfile is
|
||||||
// written on each new compilation (even when it seems unnecessary). However, it
|
// written on each new compilation (even when it seems unnecessary). However, it
|
||||||
// could in rare cases lead to a stale file fetched from the cache.
|
// could in rare cases lead to a stale file fetched from the cache.
|
||||||
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
|
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
|
||||||
// Hash input file.
|
// Hash input file.
|
||||||
fileHash, err := hashFile(abspath)
|
fileHash, err := hashFile(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,11 +67,6 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
|
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
ext := ".o"
|
|
||||||
if thinlto {
|
|
||||||
ext = ".bc"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create cache key for the dependencies file.
|
// Create cache key for the dependencies file.
|
||||||
buf, err := json.Marshal(struct {
|
buf, err := json.Marshal(struct {
|
||||||
Path string
|
Path string
|
||||||
@@ -93,7 +88,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
// Load dependencies file, if possible.
|
// Load dependencies file, if possible.
|
||||||
depfileName := "dep-" + depfileNameHash + ".json"
|
depfileName := "dep-" + depfileNameHash + ".json"
|
||||||
depfileCachePath := filepath.Join(goenv.Get("GOCACHE"), depfileName)
|
depfileCachePath := filepath.Join(goenv.Get("GOCACHE"), depfileName)
|
||||||
depfileBuf, err := os.ReadFile(depfileCachePath)
|
depfileBuf, err := ioutil.ReadFile(depfileCachePath)
|
||||||
var dependencies []string // sorted list of dependency paths
|
var dependencies []string // sorted list of dependency paths
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// There is a dependency file, that's great!
|
// There is a dependency file, that's great!
|
||||||
@@ -104,34 +99,31 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtain hashes of all the files listed as a dependency.
|
// Obtain hashes of all the files listed as a dependency.
|
||||||
outpath, err := makeCFileCachePath(dependencies, depfileNameHash, ext)
|
outpath, err := makeCFileCachePath(dependencies, depfileNameHash)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if _, err := os.Stat(outpath); err == nil {
|
if _, err := os.Stat(outpath); err == nil {
|
||||||
return outpath, nil
|
return outpath, nil
|
||||||
} else if !errors.Is(err, fs.ErrNotExist) {
|
} else if !os.IsNotExist(err) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !errors.Is(err, fs.ErrNotExist) {
|
} else if !os.IsNotExist(err) {
|
||||||
// expected either nil or IsNotExist
|
// expected either nil or IsNotExist
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
objTmpFile, err := os.CreateTemp(goenv.Get("GOCACHE"), "tmp-*"+ext)
|
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*.o")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
objTmpFile.Close()
|
objTmpFile.Close()
|
||||||
depTmpFile, err := os.CreateTemp(tmpdir, "dep-*.d")
|
depTmpFile, err := ioutil.TempFile(tmpdir, "dep-*.d")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
depTmpFile.Close()
|
depTmpFile.Close()
|
||||||
flags := append([]string{}, cflags...) // copy cflags
|
flags := append([]string{}, cflags...) // copy cflags
|
||||||
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
|
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
|
||||||
if thinlto {
|
|
||||||
flags = append(flags, "-flto=thin")
|
|
||||||
}
|
|
||||||
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
|
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
|
||||||
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
|
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
|
||||||
// If this is an assembly file (.s or .S, lowercase or uppercase), then
|
// If this is an assembly file (.s or .S, lowercase or uppercase), then
|
||||||
@@ -166,7 +158,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
sort.Strings(dependencySlice)
|
sort.Strings(dependencySlice)
|
||||||
|
|
||||||
// Write dependencies file.
|
// Write dependencies file.
|
||||||
f, err := os.CreateTemp(filepath.Dir(depfileCachePath), depfileName)
|
f, err := ioutil.TempFile(filepath.Dir(depfileCachePath), depfileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -189,7 +181,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move temporary object file to final location.
|
// Move temporary object file to final location.
|
||||||
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash, ext)
|
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -204,7 +196,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
|
|||||||
// Create a cache path (a path in GOCACHE) to store the output of a compiler
|
// Create a cache path (a path in GOCACHE) to store the output of a compiler
|
||||||
// job. This path is based on the dep file name (which is a hash of metadata
|
// job. This path is based on the dep file name (which is a hash of metadata
|
||||||
// including compiler flags) and the hash of all input files in the paths slice.
|
// including compiler flags) and the hash of all input files in the paths slice.
|
||||||
func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, error) {
|
func makeCFileCachePath(paths []string, depfileNameHash string) (string, error) {
|
||||||
// Hash all input files.
|
// Hash all input files.
|
||||||
fileHashes := make(map[string]string, len(paths))
|
fileHashes := make(map[string]string, len(paths))
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
@@ -229,7 +221,7 @@ func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, er
|
|||||||
outFileNameBuf := sha512.Sum512_224(buf)
|
outFileNameBuf := sha512.Sum512_224(buf)
|
||||||
cacheKey := hex.EncodeToString(outFileNameBuf[:])
|
cacheKey := hex.EncodeToString(outFileNameBuf[:])
|
||||||
|
|
||||||
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+ext)
|
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".o")
|
||||||
return outpath, nil
|
return outpath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,14 +244,13 @@ func hashFile(path string) (string, error) {
|
|||||||
// file is assumed to have a single target named deps.
|
// file is assumed to have a single target named deps.
|
||||||
//
|
//
|
||||||
// There are roughly three make syntax variants:
|
// There are roughly three make syntax variants:
|
||||||
// - BSD make, which doesn't support any escaping. This means that many special
|
// - BSD make, which doesn't support any escaping. This means that many special
|
||||||
// characters are not supported in file names.
|
// characters are not supported in file names.
|
||||||
// - GNU make, which supports escaping using a backslash but when it fails to
|
// - GNU make, which supports escaping using a backslash but when it fails to
|
||||||
// find a file it tries to fall back with the literal path name (to match BSD
|
// find a file it tries to fall back with the literal path name (to match BSD
|
||||||
// make).
|
// make).
|
||||||
// - NMake (Visual Studio) and Jom, which simply quote the string if there are
|
// - NMake (Visual Studio) and Jom, which simply quote the string if there are
|
||||||
// any weird characters.
|
// any weird characters.
|
||||||
//
|
|
||||||
// Clang supports two variants: a format that's a compromise between BSD and GNU
|
// Clang supports two variants: a format that's a compromise between BSD and GNU
|
||||||
// make (and is buggy to match GCC which is equally buggy), and NMake/Jom, which
|
// make (and is buggy to match GCC which is equally buggy), and NMake/Jom, which
|
||||||
// is at least somewhat sane. This last format isn't perfect either: it does not
|
// is at least somewhat sane. This last format isn't perfect either: it does not
|
||||||
@@ -267,7 +258,7 @@ func hashFile(path string) (string, error) {
|
|||||||
// allowed on Windows, but of course can be used on POSIX like systems. Still,
|
// allowed on Windows, but of course can be used on POSIX like systems. Still,
|
||||||
// it's the most sane of any of the formats so readDepFile will use that format.
|
// it's the most sane of any of the formats so readDepFile will use that format.
|
||||||
func readDepFile(filename string) ([]string, error) {
|
func readDepFile(filename string) ([]string, error) {
|
||||||
buf, err := os.ReadFile(filename)
|
buf, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -38,7 +38,6 @@
|
|||||||
#include "llvm/MC/MCStreamer.h"
|
#include "llvm/MC/MCStreamer.h"
|
||||||
#include "llvm/MC/MCSubtargetInfo.h"
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||||||
#include "llvm/MC/MCTargetOptions.h"
|
#include "llvm/MC/MCTargetOptions.h"
|
||||||
#include "llvm/MC/TargetRegistry.h"
|
|
||||||
#include "llvm/Option/Arg.h"
|
#include "llvm/Option/Arg.h"
|
||||||
#include "llvm/Option/ArgList.h"
|
#include "llvm/Option/ArgList.h"
|
||||||
#include "llvm/Option/OptTable.h"
|
#include "llvm/Option/OptTable.h"
|
||||||
@@ -52,6 +51,7 @@
|
|||||||
#include "llvm/Support/Process.h"
|
#include "llvm/Support/Process.h"
|
||||||
#include "llvm/Support/Signals.h"
|
#include "llvm/Support/Signals.h"
|
||||||
#include "llvm/Support/SourceMgr.h"
|
#include "llvm/Support/SourceMgr.h"
|
||||||
|
#include "llvm/Support/TargetRegistry.h"
|
||||||
#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"
|
||||||
@@ -120,6 +120,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||||
.Case("none", llvm::DebugCompressionType::None)
|
.Case("none", llvm::DebugCompressionType::None)
|
||||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||||
|
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
|
||||||
.Default(llvm::DebugCompressionType::None);
|
.Default(llvm::DebugCompressionType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +382,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
|
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
|
||||||
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
|
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
|
||||||
/*DWARFMustBeAtTheEnd*/ true));
|
/*DWARFMustBeAtTheEnd*/ true));
|
||||||
Str.get()->initSections(Opts.NoExecStack, *STI);
|
Str.get()->InitSections(Opts.NoExecStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
||||||
@@ -441,7 +442,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts,
|
|||||||
return Failed;
|
return Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LLVMErrorHandler(void *UserData, const char *Message,
|
static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||||
bool GenCrashDiag) {
|
bool GenCrashDiag) {
|
||||||
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
|
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ func LookupCommand(name string) (string, error) {
|
|||||||
}
|
}
|
||||||
return cmdName, nil
|
return cmdName, nil
|
||||||
}
|
}
|
||||||
return "", errors.New("none of these commands were found in your $PATH: " + strings.Join(commands[name], " "))
|
return "", errors.New("%#v: none of these commands were found in your $PATH: " + strings.Join(commands[name], " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func execCommand(name string, args ...string) error {
|
func execCommand(name string, args ...string) error {
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||||
}
|
}
|
||||||
if major != 1 || minor < 18 || minor > 19 {
|
if major != 1 || minor < 15 || minor > 17 {
|
||||||
return nil, fmt.Errorf("requires go version 1.18 through 1.19, got go%d.%d", major, minor)
|
return nil, fmt.Errorf("requires go version 1.15 through 1.17, got go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
package builder
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create a job that builds a Darwin libSystem.dylib stub library. This library
|
|
||||||
// contains all the symbols needed so that we can link against it, but it
|
|
||||||
// doesn't contain any real symbol implementations.
|
|
||||||
func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJob {
|
|
||||||
return &compileJob{
|
|
||||||
description: "compile Darwin libSystem.dylib",
|
|
||||||
run: func(job *compileJob) (err error) {
|
|
||||||
arch := strings.Split(config.Triple(), "-")[0]
|
|
||||||
job.result = filepath.Join(tmpdir, "libSystem.dylib")
|
|
||||||
objpath := filepath.Join(tmpdir, "libSystem.o")
|
|
||||||
inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s")
|
|
||||||
|
|
||||||
// Compile assembly file to object file.
|
|
||||||
flags := []string{
|
|
||||||
"-nostdlib",
|
|
||||||
"--target=" + config.Triple(),
|
|
||||||
"-c",
|
|
||||||
"-o", objpath,
|
|
||||||
inpath,
|
|
||||||
}
|
|
||||||
if config.Options.PrintCommands != nil {
|
|
||||||
config.Options.PrintCommands("clang", flags...)
|
|
||||||
}
|
|
||||||
err = runCCompiler(flags...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link object file to dynamic library.
|
|
||||||
platformVersion := strings.TrimPrefix(strings.Split(config.Triple(), "-")[2], "macosx")
|
|
||||||
flags = []string{
|
|
||||||
"-flavor", "darwin",
|
|
||||||
"-demangle",
|
|
||||||
"-dynamic",
|
|
||||||
"-dylib",
|
|
||||||
"-arch", arch,
|
|
||||||
"-platform_version", "macos", platformVersion, platformVersion,
|
|
||||||
"-install_name", "/usr/lib/libSystem.B.dylib",
|
|
||||||
"-o", job.result,
|
|
||||||
objpath,
|
|
||||||
}
|
|
||||||
if config.Options.PrintCommands != nil {
|
|
||||||
config.Options.PrintCommands("ld.lld", flags...)
|
|
||||||
}
|
|
||||||
return link("ld.lld", flags...)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-4
@@ -1,8 +1,6 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io/fs"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -19,13 +17,13 @@ import (
|
|||||||
func getClangHeaderPath(TINYGOROOT string) string {
|
func getClangHeaderPath(TINYGOROOT string) string {
|
||||||
// Check whether we're running from the source directory.
|
// Check whether we're running from the source directory.
|
||||||
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
|
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
|
||||||
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we're running from the installation directory.
|
// Check whether we're running from the installation directory.
|
||||||
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
|
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
|
||||||
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-32
@@ -13,9 +13,8 @@ import (
|
|||||||
"debug/elf"
|
"debug/elf"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"io/ioutil"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type espImageSegment struct {
|
type espImageSegment struct {
|
||||||
@@ -79,31 +78,15 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
|||||||
// An added benefit is that we don't need to check for errors all the time.
|
// An added benefit is that we don't need to check for errors all the time.
|
||||||
outf := &bytes.Buffer{}
|
outf := &bytes.Buffer{}
|
||||||
|
|
||||||
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
|
|
||||||
// image, not just a binary to be flashed at 0x1000 for example.
|
|
||||||
chip := format
|
|
||||||
makeImage := false
|
|
||||||
if strings.HasSuffix(format, "-img") {
|
|
||||||
makeImage = true
|
|
||||||
chip = format[:len(format)-len("-img")]
|
|
||||||
}
|
|
||||||
|
|
||||||
if makeImage {
|
|
||||||
// The bootloader starts at 0x1000, or 4096.
|
|
||||||
// TinyGo doesn't use a separate bootloader and runs the entire
|
|
||||||
// application in the bootloader location.
|
|
||||||
outf.Write(make([]byte, 4096))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chip IDs. Source:
|
// Chip IDs. Source:
|
||||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
|
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
|
||||||
chip_id := map[string]uint16{
|
chip_id := map[string]uint16{
|
||||||
"esp32": 0x0000,
|
"esp32": 0x0000,
|
||||||
"esp32c3": 0x0005,
|
"esp32c3": 0x0005,
|
||||||
}[chip]
|
}[format]
|
||||||
|
|
||||||
// Image header.
|
// Image header.
|
||||||
switch chip {
|
switch format {
|
||||||
case "esp32", "esp32c3":
|
case "esp32", "esp32c3":
|
||||||
// Header format:
|
// Header format:
|
||||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
||||||
@@ -172,22 +155,12 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
|||||||
outf.Write(make([]byte, 15-outf.Len()%16))
|
outf.Write(make([]byte, 15-outf.Len()%16))
|
||||||
outf.WriteByte(checksum)
|
outf.WriteByte(checksum)
|
||||||
|
|
||||||
if chip != "esp8266" {
|
if format != "esp8266" {
|
||||||
// SHA256 hash (to protect against image corruption, not for security).
|
// SHA256 hash (to protect against image corruption, not for security).
|
||||||
hash := sha256.Sum256(outf.Bytes())
|
hash := sha256.Sum256(outf.Bytes())
|
||||||
outf.Write(hash[:])
|
outf.Write(hash[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
|
|
||||||
// image to be a certain size.
|
|
||||||
if makeImage {
|
|
||||||
// Use a default image size of 4MB.
|
|
||||||
grow := 4096*1024 - outf.Len()
|
|
||||||
if grow > 0 {
|
|
||||||
outf.Write(make([]byte, grow))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the image to the output file.
|
// Write the image to the output file.
|
||||||
return os.WriteFile(outfile, outf.Bytes(), 0666)
|
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-41
@@ -1,8 +1,7 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"io/ioutil"
|
||||||
"io/fs"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -25,8 +24,8 @@ type Library struct {
|
|||||||
// cflags returns the C flags specific to this library
|
// cflags returns the C flags specific to this library
|
||||||
cflags func(target, headerPath string) []string
|
cflags func(target, headerPath string) []string
|
||||||
|
|
||||||
// The source directory.
|
// The source directory, relative to TINYGOROOT.
|
||||||
sourceDir func() string
|
sourceDir string
|
||||||
|
|
||||||
// The source files, relative to sourceDir.
|
// The source files, relative to sourceDir.
|
||||||
librarySources func(target string) []string
|
librarySources func(target string) []string
|
||||||
@@ -95,7 +94,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
target := config.Triple()
|
target := config.Triple()
|
||||||
if l.makeHeaders != nil {
|
if l.makeHeaders != nil {
|
||||||
if _, err = os.Stat(headerPath); err != nil {
|
if _, err = os.Stat(headerPath); err != nil {
|
||||||
temporaryHeaderPath, err := os.MkdirTemp(outdir, "include.tmp*")
|
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -104,17 +103,13 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
err = os.Chmod(temporaryHeaderPath, 0o755) // TempDir uses 0o700 by default
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
err = os.Rename(temporaryHeaderPath, headerPath)
|
err = os.Rename(temporaryHeaderPath, headerPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, fs.ErrExist):
|
case os.IsExist(err):
|
||||||
// Another invocation of TinyGo also seems to have already created the headers.
|
// Another invocation of TinyGo also seems to have already created the headers.
|
||||||
|
|
||||||
case runtime.GOOS == "windows" && errors.Is(err, fs.ErrPermission):
|
case runtime.GOOS == "windows" && os.IsPermission(err):
|
||||||
// On Windows, a rename with a destination directory that already
|
// On Windows, a rename with a destination directory that already
|
||||||
// exists does not result in an IsExist error, but rather in an
|
// exists does not result in an IsExist error, but rather in an
|
||||||
// access denied error. To be sure, check for this case by checking
|
// access denied error. To be sure, check for this case by checking
|
||||||
@@ -149,25 +144,12 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
// However, ARM has not done this.
|
// However, ARM has not done this.
|
||||||
if strings.HasPrefix(target, "i386") || strings.HasPrefix(target, "x86_64") {
|
if strings.HasPrefix(target, "i386") || strings.HasPrefix(target, "x86_64") {
|
||||||
args = append(args, "-march="+cpu)
|
args = append(args, "-march="+cpu)
|
||||||
} else if strings.HasPrefix(target, "avr") {
|
|
||||||
args = append(args, "-mmcu="+cpu)
|
|
||||||
} else {
|
} else {
|
||||||
args = append(args, "-mcpu="+cpu)
|
args = append(args, "-mcpu="+cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||||
if strings.Split(target, "-")[2] == "linux" {
|
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables")
|
||||||
args = append(args, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
|
||||||
} else {
|
|
||||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(target, "avr") {
|
|
||||||
// AVR defaults to C float and double both being 32-bit. This deviates
|
|
||||||
// from what most code (and certainly compiler-rt) expects. So we need
|
|
||||||
// to force the compiler to use 64-bit floating point numbers for
|
|
||||||
// double.
|
|
||||||
args = append(args, "-mdouble=64")
|
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(target, "riscv32-") {
|
if strings.HasPrefix(target, "riscv32-") {
|
||||||
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
||||||
@@ -175,12 +157,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", "-mabi=lp64")
|
args = append(args, "-march=rv64gc", "-mabi=lp64")
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
||||||
@@ -194,7 +170,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
defer once.Do(unlock)
|
defer once.Do(unlock)
|
||||||
|
|
||||||
// Create an archive of all object files.
|
// Create an archive of all object files.
|
||||||
f, err := os.CreateTemp(outdir, "libc.a.tmp*")
|
f, err := ioutil.TempFile(outdir, "libc.a.tmp*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -206,17 +182,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = os.Chmod(f.Name(), 0o644) // TempFile uses 0o600 by default
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Store this archive in the cache.
|
// Store this archive in the cache.
|
||||||
return os.Rename(f.Name(), archiveFilePath)
|
return os.Rename(f.Name(), archiveFilePath)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceDir := l.sourceDir()
|
|
||||||
|
|
||||||
// Create jobs to compile all sources. These jobs are depended upon by the
|
// Create jobs to compile all sources. These jobs are depended upon by the
|
||||||
// archive job above, so must be run first.
|
// archive job above, so must be run first.
|
||||||
for _, path := range l.librarySources(target) {
|
for _, path := range l.librarySources(target) {
|
||||||
@@ -225,7 +195,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
for strings.HasPrefix(cleanpath, "../") {
|
for strings.HasPrefix(cleanpath, "../") {
|
||||||
cleanpath = cleanpath[3:]
|
cleanpath = cleanpath[3:]
|
||||||
}
|
}
|
||||||
srcpath := filepath.Join(sourceDir, path)
|
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, path)
|
||||||
objpath := filepath.Join(dir, cleanpath+".o")
|
objpath := filepath.Join(dir, cleanpath+".o")
|
||||||
os.MkdirAll(filepath.Dir(objpath), 0o777)
|
os.MkdirAll(filepath.Dir(objpath), 0o777)
|
||||||
objs = append(objs, objpath)
|
objs = append(objs, objpath)
|
||||||
@@ -249,13 +219,13 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
// (It could be done in parallel with creating the ar file, but it probably
|
// (It could be done in parallel with creating the ar file, but it probably
|
||||||
// won't make much of a difference in speed).
|
// won't make much of a difference in speed).
|
||||||
if l.crt1Source != "" {
|
if l.crt1Source != "" {
|
||||||
srcpath := filepath.Join(sourceDir, l.crt1Source)
|
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, l.crt1Source)
|
||||||
job.dependencies = append(job.dependencies, &compileJob{
|
job.dependencies = append(job.dependencies, &compileJob{
|
||||||
description: "compile " + srcpath,
|
description: "compile " + srcpath,
|
||||||
run: func(*compileJob) error {
|
run: func(*compileJob) error {
|
||||||
var compileArgs []string
|
var compileArgs []string
|
||||||
compileArgs = append(compileArgs, args...)
|
compileArgs = append(compileArgs, args...)
|
||||||
tmpfile, err := os.CreateTemp(outdir, "crt1.o.tmp*")
|
tmpfile, err := ioutil.TempFile(outdir, "crt1.o.tmp*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-8
@@ -8,22 +8,17 @@ extern "C" {
|
|||||||
|
|
||||||
bool tinygo_link_elf(int argc, char **argv) {
|
bool tinygo_link_elf(int argc, char **argv) {
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
std::vector<const char*> args(argv, argv + argc);
|
||||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
return lld::elf::link(args, false, llvm::outs(), llvm::errs());
|
||||||
}
|
|
||||||
|
|
||||||
bool tinygo_link_macho(int argc, char **argv) {
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv) {
|
bool tinygo_link_mingw(int argc, char **argv) {
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
std::vector<const char*> args(argv, argv + argc);
|
||||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
return lld::mingw::link(args, false, llvm::outs(), llvm::errs());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tinygo_link_wasm(int argc, char **argv) {
|
bool tinygo_link_wasm(int argc, char **argv) {
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
std::vector<const char*> args(argv, argv + argc);
|
||||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
return lld::wasm::link(args, false, llvm::outs(), llvm::errs());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // external "C"
|
} // external "C"
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ var MinGW = Library{
|
|||||||
_, err = io.Copy(outf, inf)
|
_, err = io.Copy(outf, inf)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return "" }, // unused
|
|
||||||
cflags: func(target, headerPath string) []string {
|
cflags: func(target, headerPath string) []string {
|
||||||
// No flags necessary because there are no files to compile.
|
// No flags necessary because there are no files to compile.
|
||||||
return nil
|
return nil
|
||||||
@@ -78,7 +77,7 @@ func makeMinGWExtraLibs(tmpdir string) []*compileJob {
|
|||||||
// .in files need to be preprocessed by a preprocessor (-E)
|
// .in files need to be preprocessed by a preprocessor (-E)
|
||||||
// first.
|
// first.
|
||||||
defpath = outpath + ".def"
|
defpath = outpath + ".def"
|
||||||
err := runCCompiler("-E", "-x", "c", "-Wp,-w", "-P", "-DDEF_X64", "-DDATA", "-o", defpath, inpath, "-I"+goenv.Get("TINYGOROOT")+"/lib/mingw-w64/mingw-w64-crt/def-include/")
|
err := runCCompiler("-E", "-x", "c", "-Wp,-w", "-P", "-DDEF_X64", "-o", defpath, inpath, "-I"+goenv.Get("TINYGOROOT")+"/lib/mingw-w64/mingw-w64-crt/def-include/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-6
@@ -3,6 +3,7 @@ package builder
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -34,7 +35,7 @@ var Musl = Library{
|
|||||||
filepath.Join(muslDir, "include", "alltypes.h.in"),
|
filepath.Join(muslDir, "include", "alltypes.h.in"),
|
||||||
}
|
}
|
||||||
for _, infile := range infiles {
|
for _, infile := range infiles {
|
||||||
data, err := os.ReadFile(infile)
|
data, err := ioutil.ReadFile(infile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -62,7 +63,7 @@ var Musl = Library{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data, err := os.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
|
data, err := ioutil.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -89,7 +90,6 @@ var Musl = Library{
|
|||||||
"-Wno-shift-op-parentheses",
|
"-Wno-shift-op-parentheses",
|
||||||
"-Wno-ignored-attributes",
|
"-Wno-ignored-attributes",
|
||||||
"-Wno-string-plus-int",
|
"-Wno-string-plus-int",
|
||||||
"-Wno-ignored-pragmas",
|
|
||||||
"-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),
|
||||||
@@ -104,7 +104,7 @@ var Musl = Library{
|
|||||||
"-fno-stack-protector",
|
"-fno-stack-protector",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
sourceDir: "lib/musl/src",
|
||||||
librarySources: func(target string) []string {
|
librarySources: func(target string) []string {
|
||||||
arch := compileopts.MuslArchitecture(target)
|
arch := compileopts.MuslArchitecture(target)
|
||||||
globs := []string{
|
globs := []string{
|
||||||
@@ -115,10 +115,8 @@ var Musl = Library{
|
|||||||
"internal/libc.c",
|
"internal/libc.c",
|
||||||
"internal/syscall_ret.c",
|
"internal/syscall_ret.c",
|
||||||
"internal/vdso.c",
|
"internal/vdso.c",
|
||||||
"legacy/*.c",
|
|
||||||
"malloc/*.c",
|
"malloc/*.c",
|
||||||
"mman/*.c",
|
"mman/*.c",
|
||||||
"math/*.c",
|
|
||||||
"signal/*.c",
|
"signal/*.c",
|
||||||
"stdio/*.c",
|
"stdio/*.c",
|
||||||
"string/*.c",
|
"string/*.c",
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ package builder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io/ioutil"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
@@ -18,7 +18,7 @@ func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
|
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
|
||||||
cmd.Stdout = io.Discard
|
cmd.Stdout = ioutil.Discard
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
|
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ package builder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"io"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ func extractROM(path string) (uint64, []byte, error) {
|
|||||||
// Pad the difference
|
// Pad the difference
|
||||||
rom = append(rom, make([]byte, diff)...)
|
rom = append(rom, make([]byte, diff)...)
|
||||||
}
|
}
|
||||||
data, err := io.ReadAll(prog.Open())
|
data, err := ioutil.ReadAll(prog.Open())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err}
|
return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err}
|
||||||
}
|
}
|
||||||
|
|||||||
+204
-380
@@ -19,7 +19,7 @@ var Picolibc = Library{
|
|||||||
return f.Close()
|
return f.Close()
|
||||||
},
|
},
|
||||||
cflags: func(target, headerPath string) []string {
|
cflags: func(target, headerPath string) []string {
|
||||||
newlibDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib")
|
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc")
|
||||||
return []string{
|
return []string{
|
||||||
"-Werror",
|
"-Werror",
|
||||||
"-Wall",
|
"-Wall",
|
||||||
@@ -27,395 +27,219 @@ var Picolibc = Library{
|
|||||||
"-D_COMPILING_NEWLIB",
|
"-D_COMPILING_NEWLIB",
|
||||||
"-DHAVE_ALIAS_ATTRIBUTE",
|
"-DHAVE_ALIAS_ATTRIBUTE",
|
||||||
"-DTINY_STDIO",
|
"-DTINY_STDIO",
|
||||||
"-D_IEEE_LIBM",
|
|
||||||
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
|
|
||||||
"-D__OBSOLETE_MATH_DOUBLE=0",
|
|
||||||
"-nostdlibinc",
|
"-nostdlibinc",
|
||||||
"-isystem", newlibDir + "/libc/include",
|
"-isystem", picolibcDir + "/include",
|
||||||
"-I" + newlibDir + "/libc/tinystdio",
|
"-I" + picolibcDir + "/tinystdio",
|
||||||
"-I" + newlibDir + "/libm/common",
|
|
||||||
"-I" + headerPath,
|
"-I" + headerPath,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
|
sourceDir: "lib/picolibc/newlib/libc",
|
||||||
librarySources: func(target string) []string {
|
librarySources: func(target string) []string {
|
||||||
return picolibcSources
|
return picolibcSources
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var picolibcSources = []string{
|
var picolibcSources = []string{
|
||||||
"../../picolibc-stdio.c",
|
"../../../picolibc-stdio.c",
|
||||||
|
|
||||||
"libc/tinystdio/asprintf.c",
|
"tinystdio/asprintf.c",
|
||||||
"libc/tinystdio/atod_engine.c",
|
"tinystdio/atod_engine.c",
|
||||||
"libc/tinystdio/atod_ryu.c",
|
"tinystdio/atod_ryu.c",
|
||||||
"libc/tinystdio/atof_engine.c",
|
"tinystdio/atof_engine.c",
|
||||||
"libc/tinystdio/atof_ryu.c",
|
"tinystdio/atof_ryu.c",
|
||||||
//"libc/tinystdio/atold_engine.c", // have_long_double and not long_double_equals_double
|
//"tinystdio/atold_engine.c", // have_long_double and not long_double_equals_double
|
||||||
"libc/tinystdio/clearerr.c",
|
"tinystdio/clearerr.c",
|
||||||
"libc/tinystdio/compare_exchange.c",
|
"tinystdio/compare_exchange.c",
|
||||||
"libc/tinystdio/dtoa_data.c",
|
"tinystdio/dtoa_data.c",
|
||||||
"libc/tinystdio/dtoa_engine.c",
|
"tinystdio/dtoa_engine.c",
|
||||||
"libc/tinystdio/dtoa_ryu.c",
|
"tinystdio/dtoa_ryu.c",
|
||||||
"libc/tinystdio/ecvtbuf.c",
|
"tinystdio/ecvtbuf.c",
|
||||||
"libc/tinystdio/ecvt.c",
|
"tinystdio/ecvt.c",
|
||||||
"libc/tinystdio/ecvt_data.c",
|
"tinystdio/ecvt_data.c",
|
||||||
"libc/tinystdio/ecvtfbuf.c",
|
"tinystdio/ecvtfbuf.c",
|
||||||
"libc/tinystdio/ecvtf.c",
|
"tinystdio/ecvtf.c",
|
||||||
"libc/tinystdio/ecvtf_data.c",
|
"tinystdio/ecvtf_data.c",
|
||||||
"libc/tinystdio/exchange.c",
|
"tinystdio/exchange.c",
|
||||||
//"libc/tinystdio/fclose.c", // posix-io
|
//"tinystdio/fclose.c", // posix-io
|
||||||
"libc/tinystdio/fcvtbuf.c",
|
"tinystdio/fcvtbuf.c",
|
||||||
"libc/tinystdio/fcvt.c",
|
"tinystdio/fcvt.c",
|
||||||
"libc/tinystdio/fcvtfbuf.c",
|
"tinystdio/fcvtfbuf.c",
|
||||||
"libc/tinystdio/fcvtf.c",
|
"tinystdio/fcvtf.c",
|
||||||
"libc/tinystdio/fdevopen.c",
|
"tinystdio/fdevopen.c",
|
||||||
//"libc/tinystdio/fdopen.c", // posix-io
|
//"tinystdio/fdopen.c", // posix-io
|
||||||
"libc/tinystdio/feof.c",
|
"tinystdio/feof.c",
|
||||||
"libc/tinystdio/ferror.c",
|
"tinystdio/ferror.c",
|
||||||
"libc/tinystdio/fflush.c",
|
"tinystdio/fflush.c",
|
||||||
"libc/tinystdio/fgetc.c",
|
"tinystdio/fgetc.c",
|
||||||
"libc/tinystdio/fgets.c",
|
"tinystdio/fgets.c",
|
||||||
"libc/tinystdio/fileno.c",
|
"tinystdio/fileno.c",
|
||||||
"libc/tinystdio/filestrget.c",
|
"tinystdio/filestrget.c",
|
||||||
"libc/tinystdio/filestrputalloc.c",
|
"tinystdio/filestrputalloc.c",
|
||||||
"libc/tinystdio/filestrput.c",
|
"tinystdio/filestrput.c",
|
||||||
//"libc/tinystdio/fopen.c", // posix-io
|
//"tinystdio/fopen.c", // posix-io
|
||||||
"libc/tinystdio/fprintf.c",
|
"tinystdio/fprintf.c",
|
||||||
"libc/tinystdio/fputc.c",
|
"tinystdio/fputc.c",
|
||||||
"libc/tinystdio/fputs.c",
|
"tinystdio/fputs.c",
|
||||||
"libc/tinystdio/fread.c",
|
"tinystdio/fread.c",
|
||||||
"libc/tinystdio/fscanf.c",
|
"tinystdio/fscanf.c",
|
||||||
"libc/tinystdio/fseek.c",
|
"tinystdio/fseek.c",
|
||||||
"libc/tinystdio/ftell.c",
|
"tinystdio/ftell.c",
|
||||||
"libc/tinystdio/ftoa_data.c",
|
"tinystdio/ftoa_data.c",
|
||||||
"libc/tinystdio/ftoa_engine.c",
|
"tinystdio/ftoa_engine.c",
|
||||||
"libc/tinystdio/ftoa_ryu.c",
|
"tinystdio/ftoa_ryu.c",
|
||||||
"libc/tinystdio/fwrite.c",
|
"tinystdio/fwrite.c",
|
||||||
"libc/tinystdio/gcvtbuf.c",
|
"tinystdio/gcvtbuf.c",
|
||||||
"libc/tinystdio/gcvt.c",
|
"tinystdio/gcvt.c",
|
||||||
"libc/tinystdio/gcvtfbuf.c",
|
"tinystdio/gcvtfbuf.c",
|
||||||
"libc/tinystdio/gcvtf.c",
|
"tinystdio/gcvtf.c",
|
||||||
"libc/tinystdio/getchar.c",
|
"tinystdio/getchar.c",
|
||||||
"libc/tinystdio/gets.c",
|
"tinystdio/gets.c",
|
||||||
"libc/tinystdio/matchcaseprefix.c",
|
"tinystdio/matchcaseprefix.c",
|
||||||
"libc/tinystdio/perror.c",
|
"tinystdio/perror.c",
|
||||||
//"libc/tinystdio/posixiob.c", // posix-io
|
//"tinystdio/posixiob.c", // posix-io
|
||||||
//"libc/tinystdio/posixio.c", // posix-io
|
//"tinystdio/posixio.c", // posix-io
|
||||||
"libc/tinystdio/printf.c",
|
"tinystdio/printf.c",
|
||||||
"libc/tinystdio/putchar.c",
|
"tinystdio/putchar.c",
|
||||||
"libc/tinystdio/puts.c",
|
"tinystdio/puts.c",
|
||||||
"libc/tinystdio/ryu_divpow2.c",
|
"tinystdio/ryu_divpow2.c",
|
||||||
"libc/tinystdio/ryu_log10.c",
|
"tinystdio/ryu_log10.c",
|
||||||
"libc/tinystdio/ryu_log2pow5.c",
|
"tinystdio/ryu_log2pow5.c",
|
||||||
"libc/tinystdio/ryu_pow5bits.c",
|
"tinystdio/ryu_pow5bits.c",
|
||||||
"libc/tinystdio/ryu_table.c",
|
"tinystdio/ryu_table.c",
|
||||||
"libc/tinystdio/ryu_umul128.c",
|
"tinystdio/ryu_umul128.c",
|
||||||
"libc/tinystdio/scanf.c",
|
"tinystdio/scanf.c",
|
||||||
"libc/tinystdio/setbuf.c",
|
"tinystdio/setbuf.c",
|
||||||
"libc/tinystdio/setvbuf.c",
|
"tinystdio/setvbuf.c",
|
||||||
//"libc/tinystdio/sflags.c", // posix-io
|
//"tinystdio/sflags.c", // posix-io
|
||||||
"libc/tinystdio/snprintf.c",
|
"tinystdio/snprintf.c",
|
||||||
"libc/tinystdio/snprintfd.c",
|
"tinystdio/snprintfd.c",
|
||||||
"libc/tinystdio/snprintff.c",
|
"tinystdio/snprintff.c",
|
||||||
"libc/tinystdio/sprintf.c",
|
"tinystdio/sprintf.c",
|
||||||
"libc/tinystdio/sprintfd.c",
|
"tinystdio/sprintfd.c",
|
||||||
"libc/tinystdio/sprintff.c",
|
"tinystdio/sprintff.c",
|
||||||
"libc/tinystdio/sscanf.c",
|
"tinystdio/sscanf.c",
|
||||||
"libc/tinystdio/strfromd.c",
|
"tinystdio/strfromd.c",
|
||||||
"libc/tinystdio/strfromf.c",
|
"tinystdio/strfromf.c",
|
||||||
"libc/tinystdio/strtod.c",
|
"tinystdio/strtod.c",
|
||||||
"libc/tinystdio/strtod_l.c",
|
"tinystdio/strtod_l.c",
|
||||||
"libc/tinystdio/strtof.c",
|
"tinystdio/strtof.c",
|
||||||
//"libc/tinystdio/strtold.c", // have_long_double and not long_double_equals_double
|
//"tinystdio/strtold.c", // have_long_double and not long_double_equals_double
|
||||||
//"libc/tinystdio/strtold_l.c", // have_long_double and not long_double_equals_double
|
//"tinystdio/strtold_l.c", // have_long_double and not long_double_equals_double
|
||||||
"libc/tinystdio/ungetc.c",
|
"tinystdio/ungetc.c",
|
||||||
"libc/tinystdio/vasprintf.c",
|
"tinystdio/vasprintf.c",
|
||||||
"libc/tinystdio/vfiprintf.c",
|
"tinystdio/vfiprintf.c",
|
||||||
"libc/tinystdio/vfiscanf.c",
|
"tinystdio/vfiscanf.c",
|
||||||
"libc/tinystdio/vfprintf.c",
|
"tinystdio/vfprintf.c",
|
||||||
"libc/tinystdio/vfprintff.c",
|
"tinystdio/vfprintff.c",
|
||||||
"libc/tinystdio/vfscanf.c",
|
"tinystdio/vfscanf.c",
|
||||||
"libc/tinystdio/vfscanff.c",
|
"tinystdio/vfscanff.c",
|
||||||
"libc/tinystdio/vprintf.c",
|
"tinystdio/vprintf.c",
|
||||||
"libc/tinystdio/vscanf.c",
|
"tinystdio/vscanf.c",
|
||||||
"libc/tinystdio/vsnprintf.c",
|
"tinystdio/vsnprintf.c",
|
||||||
"libc/tinystdio/vsprintf.c",
|
"tinystdio/vsprintf.c",
|
||||||
"libc/tinystdio/vsscanf.c",
|
"tinystdio/vsscanf.c",
|
||||||
|
|
||||||
"libc/string/bcmp.c",
|
"string/bcmp.c",
|
||||||
"libc/string/bcopy.c",
|
"string/bcopy.c",
|
||||||
"libc/string/bzero.c",
|
"string/bzero.c",
|
||||||
"libc/string/explicit_bzero.c",
|
"string/explicit_bzero.c",
|
||||||
"libc/string/ffsl.c",
|
"string/ffsl.c",
|
||||||
"libc/string/ffsll.c",
|
"string/ffsll.c",
|
||||||
"libc/string/fls.c",
|
"string/fls.c",
|
||||||
"libc/string/flsl.c",
|
"string/flsl.c",
|
||||||
"libc/string/flsll.c",
|
"string/flsll.c",
|
||||||
"libc/string/gnu_basename.c",
|
"string/gnu_basename.c",
|
||||||
"libc/string/index.c",
|
"string/index.c",
|
||||||
"libc/string/memccpy.c",
|
"string/memccpy.c",
|
||||||
"libc/string/memchr.c",
|
"string/memchr.c",
|
||||||
"libc/string/memcmp.c",
|
"string/memcmp.c",
|
||||||
"libc/string/memcpy.c",
|
"string/memcpy.c",
|
||||||
"libc/string/memmem.c",
|
"string/memmem.c",
|
||||||
"libc/string/memmove.c",
|
"string/memmove.c",
|
||||||
"libc/string/mempcpy.c",
|
"string/mempcpy.c",
|
||||||
"libc/string/memrchr.c",
|
"string/memrchr.c",
|
||||||
"libc/string/memset.c",
|
"string/memset.c",
|
||||||
"libc/string/rawmemchr.c",
|
"string/rawmemchr.c",
|
||||||
"libc/string/rindex.c",
|
"string/rindex.c",
|
||||||
"libc/string/stpcpy.c",
|
"string/stpcpy.c",
|
||||||
"libc/string/stpncpy.c",
|
"string/stpncpy.c",
|
||||||
"libc/string/strcasecmp.c",
|
"string/strcasecmp.c",
|
||||||
"libc/string/strcasecmp_l.c",
|
"string/strcasecmp_l.c",
|
||||||
"libc/string/strcasestr.c",
|
"string/strcasestr.c",
|
||||||
"libc/string/strcat.c",
|
"string/strcat.c",
|
||||||
"libc/string/strchr.c",
|
"string/strchr.c",
|
||||||
"libc/string/strchrnul.c",
|
"string/strchrnul.c",
|
||||||
"libc/string/strcmp.c",
|
"string/strcmp.c",
|
||||||
"libc/string/strcoll.c",
|
"string/strcoll.c",
|
||||||
"libc/string/strcoll_l.c",
|
"string/strcoll_l.c",
|
||||||
"libc/string/strcpy.c",
|
"string/strcpy.c",
|
||||||
"libc/string/strcspn.c",
|
"string/strcspn.c",
|
||||||
"libc/string/strdup.c",
|
"string/strdup.c",
|
||||||
"libc/string/strerror.c",
|
"string/strerror.c",
|
||||||
"libc/string/strerror_r.c",
|
"string/strerror_r.c",
|
||||||
"libc/string/strlcat.c",
|
"string/strlcat.c",
|
||||||
"libc/string/strlcpy.c",
|
"string/strlcpy.c",
|
||||||
"libc/string/strlen.c",
|
"string/strlen.c",
|
||||||
"libc/string/strlwr.c",
|
"string/strlwr.c",
|
||||||
"libc/string/strncasecmp.c",
|
"string/strncasecmp.c",
|
||||||
"libc/string/strncasecmp_l.c",
|
"string/strncasecmp_l.c",
|
||||||
"libc/string/strncat.c",
|
"string/strncat.c",
|
||||||
"libc/string/strncmp.c",
|
"string/strncmp.c",
|
||||||
"libc/string/strncpy.c",
|
"string/strncpy.c",
|
||||||
"libc/string/strndup.c",
|
"string/strndup.c",
|
||||||
"libc/string/strnlen.c",
|
"string/strnlen.c",
|
||||||
"libc/string/strnstr.c",
|
"string/strnstr.c",
|
||||||
"libc/string/strpbrk.c",
|
"string/strpbrk.c",
|
||||||
"libc/string/strrchr.c",
|
"string/strrchr.c",
|
||||||
"libc/string/strsep.c",
|
"string/strsep.c",
|
||||||
"libc/string/strsignal.c",
|
"string/strsignal.c",
|
||||||
"libc/string/strspn.c",
|
"string/strspn.c",
|
||||||
"libc/string/strstr.c",
|
"string/strstr.c",
|
||||||
"libc/string/strtok.c",
|
"string/strtok.c",
|
||||||
"libc/string/strtok_r.c",
|
"string/strtok_r.c",
|
||||||
"libc/string/strupr.c",
|
"string/strupr.c",
|
||||||
"libc/string/strverscmp.c",
|
"string/strverscmp.c",
|
||||||
"libc/string/strxfrm.c",
|
"string/strxfrm.c",
|
||||||
"libc/string/strxfrm_l.c",
|
"string/strxfrm_l.c",
|
||||||
"libc/string/swab.c",
|
"string/swab.c",
|
||||||
"libc/string/timingsafe_bcmp.c",
|
"string/timingsafe_bcmp.c",
|
||||||
"libc/string/timingsafe_memcmp.c",
|
"string/timingsafe_memcmp.c",
|
||||||
"libc/string/u_strerr.c",
|
"string/u_strerr.c",
|
||||||
"libc/string/wcpcpy.c",
|
"string/wcpcpy.c",
|
||||||
"libc/string/wcpncpy.c",
|
"string/wcpncpy.c",
|
||||||
"libc/string/wcscasecmp.c",
|
"string/wcscasecmp.c",
|
||||||
"libc/string/wcscasecmp_l.c",
|
"string/wcscasecmp_l.c",
|
||||||
"libc/string/wcscat.c",
|
"string/wcscat.c",
|
||||||
"libc/string/wcschr.c",
|
"string/wcschr.c",
|
||||||
"libc/string/wcscmp.c",
|
"string/wcscmp.c",
|
||||||
"libc/string/wcscoll.c",
|
"string/wcscoll.c",
|
||||||
"libc/string/wcscoll_l.c",
|
"string/wcscoll_l.c",
|
||||||
"libc/string/wcscpy.c",
|
"string/wcscpy.c",
|
||||||
"libc/string/wcscspn.c",
|
"string/wcscspn.c",
|
||||||
"libc/string/wcsdup.c",
|
"string/wcsdup.c",
|
||||||
"libc/string/wcslcat.c",
|
"string/wcslcat.c",
|
||||||
"libc/string/wcslcpy.c",
|
"string/wcslcpy.c",
|
||||||
"libc/string/wcslen.c",
|
"string/wcslen.c",
|
||||||
"libc/string/wcsncasecmp.c",
|
"string/wcsncasecmp.c",
|
||||||
"libc/string/wcsncasecmp_l.c",
|
"string/wcsncasecmp_l.c",
|
||||||
"libc/string/wcsncat.c",
|
"string/wcsncat.c",
|
||||||
"libc/string/wcsncmp.c",
|
"string/wcsncmp.c",
|
||||||
"libc/string/wcsncpy.c",
|
"string/wcsncpy.c",
|
||||||
"libc/string/wcsnlen.c",
|
"string/wcsnlen.c",
|
||||||
"libc/string/wcspbrk.c",
|
"string/wcspbrk.c",
|
||||||
"libc/string/wcsrchr.c",
|
"string/wcsrchr.c",
|
||||||
"libc/string/wcsspn.c",
|
"string/wcsspn.c",
|
||||||
"libc/string/wcsstr.c",
|
"string/wcsstr.c",
|
||||||
"libc/string/wcstok.c",
|
"string/wcstok.c",
|
||||||
"libc/string/wcswidth.c",
|
"string/wcswidth.c",
|
||||||
"libc/string/wcsxfrm.c",
|
"string/wcsxfrm.c",
|
||||||
"libc/string/wcsxfrm_l.c",
|
"string/wcsxfrm_l.c",
|
||||||
"libc/string/wcwidth.c",
|
"string/wcwidth.c",
|
||||||
"libc/string/wmemchr.c",
|
"string/wmemchr.c",
|
||||||
"libc/string/wmemcmp.c",
|
"string/wmemcmp.c",
|
||||||
"libc/string/wmemcpy.c",
|
"string/wmemcpy.c",
|
||||||
"libc/string/wmemmove.c",
|
"string/wmemmove.c",
|
||||||
"libc/string/wmempcpy.c",
|
"string/wmempcpy.c",
|
||||||
"libc/string/wmemset.c",
|
"string/wmemset.c",
|
||||||
"libc/string/xpg_strerror_r.c",
|
"string/xpg_strerror_r.c",
|
||||||
|
|
||||||
"libm/common/sf_finite.c",
|
|
||||||
"libm/common/sf_copysign.c",
|
|
||||||
"libm/common/sf_modf.c",
|
|
||||||
"libm/common/sf_scalbn.c",
|
|
||||||
"libm/common/sf_cbrt.c",
|
|
||||||
"libm/common/sf_exp10.c",
|
|
||||||
"libm/common/sf_expm1.c",
|
|
||||||
"libm/common/sf_ilogb.c",
|
|
||||||
"libm/common/sf_infinity.c",
|
|
||||||
"libm/common/sf_isinf.c",
|
|
||||||
"libm/common/sf_isinff.c",
|
|
||||||
"libm/common/sf_isnan.c",
|
|
||||||
"libm/common/sf_isnanf.c",
|
|
||||||
"libm/common/sf_issignaling.c",
|
|
||||||
"libm/common/sf_log1p.c",
|
|
||||||
"libm/common/sf_nan.c",
|
|
||||||
"libm/common/sf_nextafter.c",
|
|
||||||
"libm/common/sf_pow10.c",
|
|
||||||
"libm/common/sf_rint.c",
|
|
||||||
"libm/common/sf_logb.c",
|
|
||||||
"libm/common/sf_fdim.c",
|
|
||||||
"libm/common/sf_fma.c",
|
|
||||||
"libm/common/sf_fmax.c",
|
|
||||||
"libm/common/sf_fmin.c",
|
|
||||||
"libm/common/sf_fpclassify.c",
|
|
||||||
"libm/common/sf_lrint.c",
|
|
||||||
"libm/common/sf_llrint.c",
|
|
||||||
"libm/common/sf_lround.c",
|
|
||||||
"libm/common/sf_llround.c",
|
|
||||||
"libm/common/sf_nearbyint.c",
|
|
||||||
"libm/common/sf_remquo.c",
|
|
||||||
"libm/common/sf_round.c",
|
|
||||||
"libm/common/sf_scalbln.c",
|
|
||||||
"libm/common/sf_trunc.c",
|
|
||||||
"libm/common/sf_exp.c",
|
|
||||||
"libm/common/sf_exp2.c",
|
|
||||||
"libm/common/sf_exp2_data.c",
|
|
||||||
"libm/common/sf_log.c",
|
|
||||||
"libm/common/sf_log_data.c",
|
|
||||||
"libm/common/sf_log2.c",
|
|
||||||
"libm/common/sf_log2_data.c",
|
|
||||||
"libm/common/sf_pow_log2_data.c",
|
|
||||||
"libm/common/sf_pow.c",
|
|
||||||
|
|
||||||
"libm/common/s_finite.c",
|
|
||||||
"libm/common/s_copysign.c",
|
|
||||||
"libm/common/s_modf.c",
|
|
||||||
"libm/common/s_scalbn.c",
|
|
||||||
"libm/common/s_cbrt.c",
|
|
||||||
"libm/common/s_exp10.c",
|
|
||||||
"libm/common/s_expm1.c",
|
|
||||||
"libm/common/s_ilogb.c",
|
|
||||||
"libm/common/s_infinity.c",
|
|
||||||
"libm/common/s_isinf.c",
|
|
||||||
"libm/common/s_isinfd.c",
|
|
||||||
"libm/common/s_isnan.c",
|
|
||||||
"libm/common/s_isnand.c",
|
|
||||||
"libm/common/s_issignaling.c",
|
|
||||||
"libm/common/s_log1p.c",
|
|
||||||
"libm/common/s_nan.c",
|
|
||||||
"libm/common/s_nextafter.c",
|
|
||||||
"libm/common/s_pow10.c",
|
|
||||||
"libm/common/s_rint.c",
|
|
||||||
"libm/common/s_logb.c",
|
|
||||||
"libm/common/s_log2.c",
|
|
||||||
"libm/common/s_fdim.c",
|
|
||||||
"libm/common/s_fma.c",
|
|
||||||
"libm/common/s_fmax.c",
|
|
||||||
"libm/common/s_fmin.c",
|
|
||||||
"libm/common/s_fpclassify.c",
|
|
||||||
"libm/common/s_lrint.c",
|
|
||||||
"libm/common/s_llrint.c",
|
|
||||||
"libm/common/s_lround.c",
|
|
||||||
"libm/common/s_llround.c",
|
|
||||||
"libm/common/s_nearbyint.c",
|
|
||||||
"libm/common/s_remquo.c",
|
|
||||||
"libm/common/s_round.c",
|
|
||||||
"libm/common/s_scalbln.c",
|
|
||||||
"libm/common/s_signbit.c",
|
|
||||||
"libm/common/s_trunc.c",
|
|
||||||
"libm/common/exp.c",
|
|
||||||
"libm/common/exp2.c",
|
|
||||||
"libm/common/exp_data.c",
|
|
||||||
"libm/common/math_err_with_errno.c",
|
|
||||||
"libm/common/math_err_xflow.c",
|
|
||||||
"libm/common/math_err_uflow.c",
|
|
||||||
"libm/common/math_err_oflow.c",
|
|
||||||
"libm/common/math_err_divzero.c",
|
|
||||||
"libm/common/math_err_invalid.c",
|
|
||||||
"libm/common/math_err_may_uflow.c",
|
|
||||||
"libm/common/math_err_check_uflow.c",
|
|
||||||
"libm/common/math_err_check_oflow.c",
|
|
||||||
"libm/common/log.c",
|
|
||||||
"libm/common/log_data.c",
|
|
||||||
"libm/common/log2.c",
|
|
||||||
"libm/common/log2_data.c",
|
|
||||||
"libm/common/pow.c",
|
|
||||||
"libm/common/pow_log_data.c",
|
|
||||||
|
|
||||||
"libm/math/e_acos.c",
|
|
||||||
"libm/math/e_acosh.c",
|
|
||||||
"libm/math/e_asin.c",
|
|
||||||
"libm/math/e_atan2.c",
|
|
||||||
"libm/math/e_atanh.c",
|
|
||||||
"libm/math/e_cosh.c",
|
|
||||||
"libm/math/e_exp.c",
|
|
||||||
"libm/math/ef_acos.c",
|
|
||||||
"libm/math/ef_acosh.c",
|
|
||||||
"libm/math/ef_asin.c",
|
|
||||||
"libm/math/ef_atan2.c",
|
|
||||||
"libm/math/ef_atanh.c",
|
|
||||||
"libm/math/ef_cosh.c",
|
|
||||||
"libm/math/ef_exp.c",
|
|
||||||
"libm/math/ef_fmod.c",
|
|
||||||
"libm/math/ef_hypot.c",
|
|
||||||
"libm/math/ef_j0.c",
|
|
||||||
"libm/math/ef_j1.c",
|
|
||||||
"libm/math/ef_jn.c",
|
|
||||||
"libm/math/ef_lgamma.c",
|
|
||||||
"libm/math/ef_log10.c",
|
|
||||||
"libm/math/ef_log.c",
|
|
||||||
"libm/math/e_fmod.c",
|
|
||||||
"libm/math/ef_pow.c",
|
|
||||||
"libm/math/ef_remainder.c",
|
|
||||||
"libm/math/ef_rem_pio2.c",
|
|
||||||
"libm/math/ef_scalb.c",
|
|
||||||
"libm/math/ef_sinh.c",
|
|
||||||
"libm/math/ef_sqrt.c",
|
|
||||||
"libm/math/ef_tgamma.c",
|
|
||||||
"libm/math/e_hypot.c",
|
|
||||||
"libm/math/e_j0.c",
|
|
||||||
"libm/math/e_j1.c",
|
|
||||||
"libm/math/e_jn.c",
|
|
||||||
"libm/math/e_lgamma.c",
|
|
||||||
"libm/math/e_log10.c",
|
|
||||||
"libm/math/e_log.c",
|
|
||||||
"libm/math/e_pow.c",
|
|
||||||
"libm/math/e_remainder.c",
|
|
||||||
"libm/math/e_rem_pio2.c",
|
|
||||||
"libm/math/erf_lgamma.c",
|
|
||||||
"libm/math/er_lgamma.c",
|
|
||||||
"libm/math/e_scalb.c",
|
|
||||||
"libm/math/e_sinh.c",
|
|
||||||
"libm/math/e_sqrt.c",
|
|
||||||
"libm/math/e_tgamma.c",
|
|
||||||
"libm/math/s_asinh.c",
|
|
||||||
"libm/math/s_atan.c",
|
|
||||||
"libm/math/s_ceil.c",
|
|
||||||
"libm/math/s_cos.c",
|
|
||||||
"libm/math/s_erf.c",
|
|
||||||
"libm/math/s_fabs.c",
|
|
||||||
"libm/math/sf_asinh.c",
|
|
||||||
"libm/math/sf_atan.c",
|
|
||||||
"libm/math/sf_ceil.c",
|
|
||||||
"libm/math/sf_cos.c",
|
|
||||||
"libm/math/sf_erf.c",
|
|
||||||
"libm/math/sf_fabs.c",
|
|
||||||
"libm/math/sf_floor.c",
|
|
||||||
"libm/math/sf_frexp.c",
|
|
||||||
"libm/math/sf_ldexp.c",
|
|
||||||
"libm/math/s_floor.c",
|
|
||||||
"libm/math/s_frexp.c",
|
|
||||||
"libm/math/sf_signif.c",
|
|
||||||
"libm/math/sf_sin.c",
|
|
||||||
"libm/math/sf_tan.c",
|
|
||||||
"libm/math/sf_tanh.c",
|
|
||||||
"libm/math/s_ldexp.c",
|
|
||||||
"libm/math/s_signif.c",
|
|
||||||
"libm/math/s_sin.c",
|
|
||||||
"libm/math/s_tan.c",
|
|
||||||
"libm/math/s_tanh.c",
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-193
@@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"debug/dwarf"
|
"debug/dwarf"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"debug/macho"
|
|
||||||
"debug/pe"
|
"debug/pe"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -117,7 +116,7 @@ var (
|
|||||||
// alloc: heap allocations during init interpretation
|
// alloc: heap allocations during init interpretation
|
||||||
// pack: data created when storing a constant in an interface for example
|
// pack: data created when storing a constant in an interface for example
|
||||||
// string: buffer behind strings
|
// string: buffer behind strings
|
||||||
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|embedfsfiles|embedfsslice|embedslice|pack|string)(\.[0-9]+)?$`)
|
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|pack|string)(\.[0-9]+)?$`)
|
||||||
|
|
||||||
// Reflect sidetables. Created by the reflect lowering pass.
|
// Reflect sidetables. Created by the reflect lowering pass.
|
||||||
// See src/reflect/sidetables.go.
|
// See src/reflect/sidetables.go.
|
||||||
@@ -127,7 +126,7 @@ var (
|
|||||||
// readProgramSizeFromDWARF reads the source location for each line of code and
|
// readProgramSizeFromDWARF reads the source location for each line of code and
|
||||||
// each variable in the program, as far as this is stored in the DWARF debug
|
// each variable in the program, as far as this is stored in the DWARF debug
|
||||||
// information.
|
// information.
|
||||||
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone bool) ([]addressLine, error) {
|
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64) ([]addressLine, error) {
|
||||||
r := data.Reader()
|
r := data.Reader()
|
||||||
var lines []*dwarf.LineFile
|
var lines []*dwarf.LineFile
|
||||||
var addresses []addressLine
|
var addresses []addressLine
|
||||||
@@ -169,7 +168,7 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if prevLineEntry.EndSequence && lineEntry.Address == 0 && skipTombstone {
|
if prevLineEntry.EndSequence && lineEntry.Address == 0 {
|
||||||
// Tombstone value. This symbol has been removed, for
|
// Tombstone value. This symbol has been removed, for
|
||||||
// example by the --gc-sections linker flag. It is still
|
// example by the --gc-sections linker flag. It is still
|
||||||
// here in the debug information because the linker can't
|
// here in the debug information because the linker can't
|
||||||
@@ -178,10 +177,6 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
|||||||
// skipped.
|
// skipped.
|
||||||
// For more details, see (among others):
|
// For more details, see (among others):
|
||||||
// https://reviews.llvm.org/D84825
|
// https://reviews.llvm.org/D84825
|
||||||
// The value 0 can however really occur in object files,
|
|
||||||
// that typically start at address 0. So don't skip
|
|
||||||
// tombstone values in object files (like when parsing MachO
|
|
||||||
// files).
|
|
||||||
for {
|
for {
|
||||||
err := lr.Next(&lineEntry)
|
err := lr.Next(&lineEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -260,65 +255,6 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
|
|||||||
return addresses, nil
|
return addresses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a MachO object file and return a line table.
|
|
||||||
// Also return an index from symbol name to start address in the line table.
|
|
||||||
func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error) {
|
|
||||||
// Some constants from mach-o/nlist.h
|
|
||||||
// See: https://opensource.apple.com/source/xnu/xnu-7195.141.2/EXTERNAL_HEADERS/mach-o/nlist.h.auto.html
|
|
||||||
const (
|
|
||||||
N_STAB = 0xe0
|
|
||||||
N_TYPE = 0x0e // bitmask for N_TYPE field
|
|
||||||
N_SECT = 0xe // one of the possible type in the N_TYPE field
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read DWARF from the given object file.
|
|
||||||
file, err := macho.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
dwarf, err := file.DWARF()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
lines, err := readProgramSizeFromDWARF(dwarf, 0, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a map from start addresses to indices in the line table (because the
|
|
||||||
// line table is a slice, not a map).
|
|
||||||
addressToLine := make(map[uint64]int, len(lines))
|
|
||||||
for i, line := range lines {
|
|
||||||
if _, ok := addressToLine[line.Address]; ok {
|
|
||||||
addressToLine[line.Address] = -1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addressToLine[line.Address] = i
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a map that for each symbol gives the start index in the line table.
|
|
||||||
addresses := make(map[string]int, len(addressToLine))
|
|
||||||
for _, symbol := range file.Symtab.Syms {
|
|
||||||
if symbol.Type&N_STAB != 0 {
|
|
||||||
continue // STABS entry, ignore
|
|
||||||
}
|
|
||||||
if symbol.Type&0x0e != N_SECT {
|
|
||||||
continue // undefined symbol
|
|
||||||
}
|
|
||||||
if index, ok := addressToLine[symbol.Value]; ok && index >= 0 {
|
|
||||||
if _, ok := addresses[symbol.Name]; ok {
|
|
||||||
// There is a duplicate. Mark it as unavailable.
|
|
||||||
addresses[symbol.Name] = -1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addresses[symbol.Name] = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return addresses, lines, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadProgramSize calculate a program/data size breakdown of each package for a
|
// loadProgramSize calculate a program/data size breakdown of each package for a
|
||||||
// given ELF file.
|
// given ELF file.
|
||||||
// If the file doesn't contain DWARF debug information, the returned program
|
// If the file doesn't contain DWARF debug information, the returned program
|
||||||
@@ -341,7 +277,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
|||||||
// Read DWARF information. The error is intentionally ignored.
|
// Read DWARF information. The error is intentionally ignored.
|
||||||
data, _ := file.DWARF()
|
data, _ := file.DWARF()
|
||||||
if data != nil {
|
if data != nil {
|
||||||
addresses, err = readProgramSizeFromDWARF(data, 0, true)
|
addresses, err = readProgramSizeFromDWARF(data, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// However, _do_ report an error here. Something must have gone
|
// However, _do_ report an error here. Something must have gone
|
||||||
// wrong while trying to parse DWARF data.
|
// wrong while trying to parse DWARF data.
|
||||||
@@ -432,133 +368,11 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if file, err := macho.NewFile(f); err == nil {
|
|
||||||
// Read segments, for use while reading through sections.
|
|
||||||
segments := map[string]*macho.Segment{}
|
|
||||||
for _, load := range file.Loads {
|
|
||||||
switch load := load.(type) {
|
|
||||||
case *macho.Segment:
|
|
||||||
segments[load.Name] = load
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read MachO sections.
|
|
||||||
for _, section := range file.Sections {
|
|
||||||
sectionType := section.Flags & 0xff
|
|
||||||
sectionFlags := section.Flags >> 8
|
|
||||||
segment := segments[section.Seg]
|
|
||||||
// For the constants used here, see:
|
|
||||||
// https://github.com/llvm/llvm-project/blob/release/14.x/llvm/include/llvm/BinaryFormat/MachO.h
|
|
||||||
if sectionFlags&0x800000 != 0 { // S_ATTR_PURE_INSTRUCTIONS
|
|
||||||
// Section containing only instructions.
|
|
||||||
sections = append(sections, memorySection{
|
|
||||||
Address: section.Addr,
|
|
||||||
Size: uint64(section.Size),
|
|
||||||
Type: memoryCode,
|
|
||||||
})
|
|
||||||
} else if sectionType == 1 { // S_ZEROFILL
|
|
||||||
// Section filled with zeroes on demand.
|
|
||||||
sections = append(sections, memorySection{
|
|
||||||
Address: section.Addr,
|
|
||||||
Size: uint64(section.Size),
|
|
||||||
Type: memoryBSS,
|
|
||||||
})
|
|
||||||
} else if segment.Maxprot&0b011 == 0b001 { // --r (read-only data)
|
|
||||||
// Protection doesn't allow writes, so mark this section read-only.
|
|
||||||
sections = append(sections, memorySection{
|
|
||||||
Address: section.Addr,
|
|
||||||
Size: uint64(section.Size),
|
|
||||||
Type: memoryROData,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// The rest is assumed to be regular data.
|
|
||||||
sections = append(sections, memorySection{
|
|
||||||
Address: section.Addr,
|
|
||||||
Size: uint64(section.Size),
|
|
||||||
Type: memoryData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read DWARF information.
|
|
||||||
// The data isn't stored directly in the binary as in most executable
|
|
||||||
// formats. Instead, it is left in the object files that were used as a
|
|
||||||
// basis for linking. The executable does however contain STABS debug
|
|
||||||
// information that points to the source object file and is used by
|
|
||||||
// debuggers.
|
|
||||||
// For more information:
|
|
||||||
// http://wiki.dwarfstd.org/index.php?title=Apple%27s_%22Lazy%22_DWARF_Scheme
|
|
||||||
var objSymbolNames map[string]int
|
|
||||||
var objAddresses []addressLine
|
|
||||||
var previousSymbol macho.Symbol
|
|
||||||
for _, symbol := range file.Symtab.Syms {
|
|
||||||
// STABS constants, from mach-o/stab.h:
|
|
||||||
// https://opensource.apple.com/source/xnu/xnu-7195.141.2/EXTERNAL_HEADERS/mach-o/stab.h.auto.html
|
|
||||||
const (
|
|
||||||
N_GSYM = 0x20
|
|
||||||
N_FUN = 0x24
|
|
||||||
N_STSYM = 0x26
|
|
||||||
N_SO = 0x64
|
|
||||||
N_OSO = 0x66
|
|
||||||
)
|
|
||||||
if symbol.Type == N_OSO {
|
|
||||||
// Found an object file. Now try to parse it.
|
|
||||||
objSymbolNames, objAddresses, err = readMachOSymbolAddresses(symbol.Name)
|
|
||||||
if err != nil && sizesDebug {
|
|
||||||
// Errors are normally ignored. If there is an error, it's
|
|
||||||
// simply treated as that the DWARF is not available.
|
|
||||||
fmt.Fprintf(os.Stderr, "could not read DWARF from file %s: %s\n", symbol.Name, err)
|
|
||||||
}
|
|
||||||
} else if symbol.Type == N_FUN {
|
|
||||||
// Found a function.
|
|
||||||
// The way this is encoded is a bit weird. MachO symbols don't
|
|
||||||
// have a length. What I've found is that the length is encoded
|
|
||||||
// by first having a N_FUN symbol as usual, and then having a
|
|
||||||
// symbol with a zero-length name that has the value not set to
|
|
||||||
// the address of the symbol but to the length. So in order to
|
|
||||||
// get both the address and the length, we look for a symbol
|
|
||||||
// with a name followed by a symbol without a name.
|
|
||||||
if symbol.Name == "" && previousSymbol.Type == N_FUN && previousSymbol.Name != "" {
|
|
||||||
// Functions are encoded as many small chunks in the line
|
|
||||||
// table (one or a few instructions per source line). But
|
|
||||||
// the symbol length covers the whole symbols, over many
|
|
||||||
// lines and possibly including inlined functions. So we
|
|
||||||
// continue to iterate through the objAddresses slice until
|
|
||||||
// we've found all the source lines that are part of this
|
|
||||||
// symbol.
|
|
||||||
address := previousSymbol.Value
|
|
||||||
length := symbol.Value
|
|
||||||
if index, ok := objSymbolNames[previousSymbol.Name]; ok && index >= 0 {
|
|
||||||
for length > 0 {
|
|
||||||
line := objAddresses[index]
|
|
||||||
line.Address = address
|
|
||||||
if line.Length > length {
|
|
||||||
// Line extends beyond the end of te symbol?
|
|
||||||
// Weird, shouldn't happen.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
addresses = append(addresses, line)
|
|
||||||
index++
|
|
||||||
length -= line.Length
|
|
||||||
address += line.Length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if symbol.Type == N_GSYM || symbol.Type == N_STSYM {
|
|
||||||
// Global variables.
|
|
||||||
if index, ok := objSymbolNames[symbol.Name]; ok {
|
|
||||||
address := objAddresses[index]
|
|
||||||
address.Address = symbol.Value
|
|
||||||
addresses = append(addresses, address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
previousSymbol = symbol
|
|
||||||
}
|
|
||||||
} else if file, err := pe.NewFile(f); err == nil {
|
} else if file, err := pe.NewFile(f); err == nil {
|
||||||
// Read DWARF information. The error is intentionally ignored.
|
// Read DWARF information. The error is intentionally ignored.
|
||||||
data, _ := file.DWARF()
|
data, _ := file.DWARF()
|
||||||
if data != nil {
|
if data != nil {
|
||||||
addresses, err = readProgramSizeFromDWARF(data, 0, true)
|
addresses, err = readProgramSizeFromDWARF(data, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// However, _do_ report an error here. Something must have gone
|
// However, _do_ report an error here. Something must have gone
|
||||||
// wrong while trying to parse DWARF data.
|
// wrong while trying to parse DWARF data.
|
||||||
@@ -628,9 +442,9 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
|||||||
const codeOffset = 0x8000_0000_0000_0000
|
const codeOffset = 0x8000_0000_0000_0000
|
||||||
|
|
||||||
// Read DWARF information. The error is intentionally ignored.
|
// Read DWARF information. The error is intentionally ignored.
|
||||||
data, _ := file.DWARF()
|
data, err := file.DWARF()
|
||||||
if data != nil {
|
if data != nil {
|
||||||
addresses, err = readProgramSizeFromDWARF(data, codeOffset, true)
|
addresses, err = readProgramSizeFromDWARF(data, codeOffset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// However, _do_ report an error here. Something must have gone
|
// However, _do_ report an error here. Something must have gone
|
||||||
// wrong while trying to parse DWARF data.
|
// wrong while trying to parse DWARF data.
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
//go:build byollvm
|
|
||||||
// +build byollvm
|
// +build byollvm
|
||||||
|
|
||||||
package builder
|
package builder
|
||||||
@@ -14,7 +13,6 @@ import (
|
|||||||
#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_elf(int argc, char **argv);
|
||||||
bool tinygo_link_macho(int argc, char **argv);
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv);
|
bool tinygo_link_mingw(int argc, char **argv);
|
||||||
bool tinygo_link_wasm(int argc, char **argv);
|
bool tinygo_link_wasm(int argc, char **argv);
|
||||||
*/
|
*/
|
||||||
@@ -28,13 +26,8 @@ const hasBuiltinTools = true
|
|||||||
// 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"
|
linker := "elf"
|
||||||
if tool == "ld.lld" && len(args) >= 2 {
|
if tool == "ld.lld" && len(args) >= 2 && args[0] == "-m" && args[1] == "i386pep" {
|
||||||
if args[0] == "-m" && args[1] == "i386pep" {
|
linker = "mingw"
|
||||||
linker = "mingw"
|
|
||||||
} else if args[0] == "-flavor" {
|
|
||||||
linker = args[1]
|
|
||||||
args = args[2:]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
args = append([]string{"tinygo:" + tool}, args...)
|
args = append([]string{"tinygo:" + tool}, args...)
|
||||||
|
|
||||||
@@ -54,8 +47,6 @@ func RunTool(tool string, args ...string) error {
|
|||||||
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":
|
||||||
switch linker {
|
switch linker {
|
||||||
case "darwin":
|
|
||||||
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
|
|
||||||
case "elf":
|
case "elf":
|
||||||
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
|
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
|
||||||
case "mingw":
|
case "mingw":
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
//go:build !byollvm
|
|
||||||
// +build !byollvm
|
// +build !byollvm
|
||||||
|
|
||||||
package builder
|
package builder
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ package builder
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"os"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ func convertELFFileToUF2File(infile, outfile string, uf2FamilyID string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(outfile, output, 0644)
|
return ioutil.WriteFile(outfile, output, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
|
// convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
|
||||||
|
|||||||
+551
-429
File diff suppressed because it is too large
Load Diff
+19
-4
@@ -5,11 +5,12 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/build"
|
||||||
"go/format"
|
"go/format"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"os"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -39,6 +40,20 @@ func TestCGo(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
name := name // avoid a race condition
|
name := name // avoid a race condition
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
|
// Skip tests that require specific Go version.
|
||||||
|
if name == "errors" {
|
||||||
|
ok := false
|
||||||
|
for _, version := range build.Default.ReleaseTags {
|
||||||
|
if version == "go1.16" {
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Skip("Results for errors test are only valid for Go 1.16+")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read the AST in memory.
|
// Read the AST in memory.
|
||||||
path := filepath.Join("testdata", name+".go")
|
path := filepath.Join("testdata", name+".go")
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
@@ -48,7 +63,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, "")
|
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
|
||||||
|
|
||||||
// Check the AST for type errors.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
var typecheckErrors []error
|
||||||
@@ -92,7 +107,7 @@ func TestCGo(t *testing.T) {
|
|||||||
|
|
||||||
// Read the file with the expected output, to compare against.
|
// Read the file with the expected output, to compare against.
|
||||||
outfile := filepath.Join("testdata", name+".out.go")
|
outfile := filepath.Join("testdata", name+".out.go")
|
||||||
expectedBytes, err := os.ReadFile(outfile)
|
expectedBytes, err := ioutil.ReadFile(outfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not read expected output: %v", err)
|
t.Fatalf("could not read expected output: %v", err)
|
||||||
}
|
}
|
||||||
@@ -103,7 +118,7 @@ func TestCGo(t *testing.T) {
|
|||||||
// It is not. Test failed.
|
// It is not. Test failed.
|
||||||
if *flagUpdate {
|
if *flagUpdate {
|
||||||
// Update the file with the expected data.
|
// Update the file with the expected data.
|
||||||
err := os.WriteFile(outfile, []byte(actual), 0666)
|
err := ioutil.WriteFile(outfile, []byte(actual), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("could not write updated output file:", err)
|
t.Error("could not write updated output file:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+200
-426
@@ -4,9 +4,7 @@ package cgo
|
|||||||
// modification. It does not touch the AST itself.
|
// modification. It does not touch the AST itself.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
@@ -15,13 +13,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"tinygo.org/x/go-llvm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
|
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
|
||||||
#include <llvm/Config/llvm-config.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -45,8 +40,6 @@ typedef struct {
|
|||||||
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
|
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
|
||||||
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
|
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
|
||||||
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
|
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
|
||||||
CXString tinygo_clang_getCursorPrettyPrinted(GoCXCursor c, CXPrintingPolicy Policy);
|
|
||||||
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(GoCXCursor c);
|
|
||||||
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
|
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
|
||||||
CXType tinygo_clang_getCursorType(GoCXCursor c);
|
CXType tinygo_clang_getCursorType(GoCXCursor c);
|
||||||
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
|
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
|
||||||
@@ -54,7 +47,6 @@ CXType tinygo_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
|
|||||||
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
|
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
|
||||||
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
|
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
|
||||||
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
||||||
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(GoCXCursor c);
|
|
||||||
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
||||||
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
||||||
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
||||||
@@ -80,21 +72,7 @@ var diagnosticSeverity = [...]string{
|
|||||||
C.CXDiagnostic_Fatal: "fatal",
|
C.CXDiagnostic_Fatal: "fatal",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias so that cgo.go (which doesn't import Clang related stuff and is in
|
func (p *cgoPackage) parseFragment(fragment string, cflags []string, filename string) {
|
||||||
// theory decoupled from Clang) can also use this type.
|
|
||||||
type clangCursor = C.GoCXCursor
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Check that we haven't messed up LLVM versioning.
|
|
||||||
// This can happen when llvm_config_*.go files in either this or the
|
|
||||||
// tinygo.org/x/go-llvm packages is incorrect. It should not ever happen
|
|
||||||
// with byollvm.
|
|
||||||
if C.LLVM_VERSION_STRING != llvm.Version {
|
|
||||||
panic("incorrect build: using LLVM version " + llvm.Version + " in the tinygo.org/x/llvm package, and version " + C.LLVM_VERSION_STRING + " in the ./cgo package")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *cgoFile) readNames(fragment string, cflags []string, filename string, callback func(map[string]clangCursor)) {
|
|
||||||
index := C.clang_createIndex(0, 0)
|
index := C.clang_createIndex(0, 0)
|
||||||
defer C.clang_disposeIndex(index)
|
defer C.clang_disposeIndex(index)
|
||||||
|
|
||||||
@@ -141,8 +119,8 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
|||||||
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
|
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
|
||||||
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
|
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
|
||||||
location := C.clang_getDiagnosticLocation(diagnostic)
|
location := C.clang_getDiagnosticLocation(diagnostic)
|
||||||
pos := f.getClangLocationPosition(location, unit)
|
pos := p.getClangLocationPosition(location, unit)
|
||||||
f.addError(pos, severity+": "+spelling)
|
p.addError(pos, severity+": "+spelling)
|
||||||
}
|
}
|
||||||
for i := 0; i < numDiagnostics; i++ {
|
for i := 0; i < numDiagnostics; i++ {
|
||||||
diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
|
diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
|
||||||
@@ -157,7 +135,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract information required by CGo.
|
// Extract information required by CGo.
|
||||||
ref := storedRefs.Put(f)
|
ref := storedRefs.Put(p)
|
||||||
defer storedRefs.Remove(ref)
|
defer storedRefs.Remove(ref)
|
||||||
cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
|
cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
|
||||||
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
|
||||||
@@ -177,88 +155,35 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
|||||||
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
|
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
|
||||||
|
|
||||||
// Hash the contents if it isn't hashed yet.
|
// Hash the contents if it isn't hashed yet.
|
||||||
if _, ok := f.visitedFiles[path]; !ok {
|
if _, ok := p.visitedFiles[path]; !ok {
|
||||||
// already stored
|
// already stored
|
||||||
sum := sha512.Sum512_224(data)
|
sum := sha512.Sum512_224(data)
|
||||||
f.visitedFiles[path] = sum[:]
|
p.visitedFiles[path] = sum[:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inclusionCallbackRef := storedRefs.Put(inclusionCallback)
|
inclusionCallbackRef := storedRefs.Put(inclusionCallback)
|
||||||
defer storedRefs.Remove(inclusionCallbackRef)
|
defer storedRefs.Remove(inclusionCallbackRef)
|
||||||
C.clang_getInclusions(unit, C.CXInclusionVisitor(C.tinygo_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef))
|
C.clang_getInclusions(unit, C.CXInclusionVisitor(C.tinygo_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef))
|
||||||
|
|
||||||
// Do all the C AST operations inside a callback. This makes sure that
|
|
||||||
// libclang related memory is only freed after it is not necessary anymore.
|
|
||||||
callback(f.names)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the AST node under the given Clang cursor to a Go AST node and return
|
//export tinygo_clang_globals_visitor
|
||||||
// it.
|
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
|
||||||
kind := C.tinygo_clang_getCursorKind(c)
|
kind := C.tinygo_clang_getCursorKind(c)
|
||||||
pos := f.getCursorPosition(c)
|
pos := p.getCursorPosition(c)
|
||||||
switch kind {
|
switch kind {
|
||||||
case C.CXCursor_FunctionDecl:
|
case C.CXCursor_FunctionDecl:
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
|
}
|
||||||
cursorType := C.tinygo_clang_getCursorType(c)
|
cursorType := C.tinygo_clang_getCursorType(c)
|
||||||
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
||||||
obj := &ast.Object{
|
fn := &functionInfo{
|
||||||
Kind: ast.Fun,
|
pos: pos,
|
||||||
Name: "C." + name,
|
variadic: C.clang_isFunctionTypeVariadic(cursorType) != 0,
|
||||||
}
|
|
||||||
exportName := name
|
|
||||||
localName := name
|
|
||||||
var stringSignature string
|
|
||||||
if C.tinygo_clang_Cursor_getStorageClass(c) == C.CX_SC_Static {
|
|
||||||
// A static function is assigned a globally unique symbol name based
|
|
||||||
// on the file path (like _Cgo_static_2d09198adbf58f4f4655_foo) and
|
|
||||||
// has a different Go name in the form of C.foo!symbols.go instead
|
|
||||||
// of just C.foo.
|
|
||||||
path := f.importPath + "/" + filepath.Base(f.fset.File(f.file.Pos()).Name())
|
|
||||||
staticIDBuf := sha256.Sum256([]byte(path))
|
|
||||||
staticID := hex.EncodeToString(staticIDBuf[:10])
|
|
||||||
exportName = "_Cgo_static_" + staticID + "_" + name
|
|
||||||
localName = name + "!" + filepath.Base(path)
|
|
||||||
|
|
||||||
// Create a signature. This is necessary for MacOS to forward the
|
|
||||||
// call, because MacOS doesn't support aliases like ELF and PE do.
|
|
||||||
// (There is N_INDR but __attribute__((alias("..."))) doesn't work).
|
|
||||||
policy := C.tinygo_clang_getCursorPrintingPolicy(c)
|
|
||||||
defer C.clang_PrintingPolicy_dispose(policy)
|
|
||||||
C.clang_PrintingPolicy_setProperty(policy, C.CXPrintingPolicy_TerseOutput, 1)
|
|
||||||
stringSignature = getString(C.tinygo_clang_getCursorPrettyPrinted(c, policy))
|
|
||||||
stringSignature = strings.Replace(stringSignature, " "+name+"(", " "+exportName+"(", 1)
|
|
||||||
stringSignature = strings.TrimPrefix(stringSignature, "static ")
|
|
||||||
}
|
|
||||||
args := make([]*ast.Field, numArgs)
|
|
||||||
decl := &ast.FuncDecl{
|
|
||||||
Doc: &ast.CommentGroup{
|
|
||||||
List: []*ast.Comment{
|
|
||||||
{
|
|
||||||
Slash: pos - 1,
|
|
||||||
Text: "//export " + exportName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: "C." + localName,
|
|
||||||
Obj: obj,
|
|
||||||
},
|
|
||||||
Type: &ast.FuncType{
|
|
||||||
Func: pos,
|
|
||||||
Params: &ast.FieldList{
|
|
||||||
Opening: pos,
|
|
||||||
List: args,
|
|
||||||
Closing: pos,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
|
|
||||||
decl.Doc.List = append(decl.Doc.List, &ast.Comment{
|
|
||||||
Slash: pos - 1,
|
|
||||||
Text: "//go:variadic",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
p.functions[name] = fn
|
||||||
for i := 0; i < numArgs; i++ {
|
for i := 0; i < numArgs; i++ {
|
||||||
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
|
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
|
||||||
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
|
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
|
||||||
@@ -266,108 +191,50 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
|||||||
if argName == "" {
|
if argName == "" {
|
||||||
argName = "$" + strconv.Itoa(i)
|
argName = "$" + strconv.Itoa(i)
|
||||||
}
|
}
|
||||||
args[i] = &ast.Field{
|
fn.args = append(fn.args, paramInfo{
|
||||||
Names: []*ast.Ident{
|
name: argName,
|
||||||
{
|
typeExpr: p.makeDecayingASTType(argType, pos),
|
||||||
NamePos: pos,
|
})
|
||||||
Name: argName,
|
|
||||||
Obj: &ast.Object{
|
|
||||||
Kind: ast.Var,
|
|
||||||
Name: argName,
|
|
||||||
Decl: decl,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: f.makeDecayingASTType(argType, pos),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
resultType := C.tinygo_clang_getCursorResultType(c)
|
resultType := C.tinygo_clang_getCursorResultType(c)
|
||||||
if resultType.kind != C.CXType_Void {
|
if resultType.kind != C.CXType_Void {
|
||||||
decl.Type.Results = &ast.FieldList{
|
fn.results = &ast.FieldList{
|
||||||
List: []*ast.Field{
|
List: []*ast.Field{
|
||||||
{
|
{
|
||||||
Type: f.makeASTType(resultType, pos),
|
Type: p.makeASTType(resultType, pos),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj.Decl = decl
|
case C.CXCursor_StructDecl:
|
||||||
return decl, stringSignature
|
typ := C.tinygo_clang_getCursorType(c)
|
||||||
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
typ := f.makeASTRecordType(c, pos)
|
if _, required := p.missingSymbols["struct_"+name]; !required {
|
||||||
typeName := "C." + name
|
return C.CXChildVisit_Continue
|
||||||
typeExpr := typ.typeExpr
|
|
||||||
if typ.unionSize != 0 {
|
|
||||||
// Convert to a single-field struct type.
|
|
||||||
typeExpr = f.makeUnionField(typ)
|
|
||||||
}
|
}
|
||||||
obj := &ast.Object{
|
p.makeASTType(typ, pos)
|
||||||
Kind: ast.Typ,
|
|
||||||
Name: typeName,
|
|
||||||
}
|
|
||||||
typeSpec := &ast.TypeSpec{
|
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: typ.pos,
|
|
||||||
Name: typeName,
|
|
||||||
Obj: obj,
|
|
||||||
},
|
|
||||||
Type: typeExpr,
|
|
||||||
}
|
|
||||||
obj.Decl = typeSpec
|
|
||||||
return typeSpec, typ
|
|
||||||
case C.CXCursor_TypedefDecl:
|
case C.CXCursor_TypedefDecl:
|
||||||
typeName := "C." + name
|
typedefType := C.tinygo_clang_getCursorType(c)
|
||||||
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
name := getString(C.clang_getTypedefName(typedefType))
|
||||||
obj := &ast.Object{
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
Kind: ast.Typ,
|
return C.CXChildVisit_Continue
|
||||||
Name: typeName,
|
|
||||||
}
|
}
|
||||||
typeSpec := &ast.TypeSpec{
|
p.makeASTType(typedefType, pos)
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: typeName,
|
|
||||||
Obj: obj,
|
|
||||||
},
|
|
||||||
Type: f.makeASTType(underlyingType, pos),
|
|
||||||
}
|
|
||||||
if underlyingType.kind != C.CXType_Enum {
|
|
||||||
typeSpec.Assign = pos
|
|
||||||
}
|
|
||||||
obj.Decl = typeSpec
|
|
||||||
return typeSpec, nil
|
|
||||||
case C.CXCursor_VarDecl:
|
case C.CXCursor_VarDecl:
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
|
}
|
||||||
cursorType := C.tinygo_clang_getCursorType(c)
|
cursorType := C.tinygo_clang_getCursorType(c)
|
||||||
typeExpr := f.makeASTType(cursorType, pos)
|
p.globals[name] = globalInfo{
|
||||||
gen := &ast.GenDecl{
|
typeExpr: p.makeASTType(cursorType, pos),
|
||||||
TokPos: pos,
|
pos: pos,
|
||||||
Tok: token.VAR,
|
|
||||||
Lparen: token.NoPos,
|
|
||||||
Rparen: token.NoPos,
|
|
||||||
Doc: &ast.CommentGroup{
|
|
||||||
List: []*ast.Comment{
|
|
||||||
{
|
|
||||||
Slash: pos - 1,
|
|
||||||
Text: "//go:extern " + name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
obj := &ast.Object{
|
|
||||||
Kind: ast.Var,
|
|
||||||
Name: "C." + name,
|
|
||||||
}
|
|
||||||
valueSpec := &ast.ValueSpec{
|
|
||||||
Names: []*ast.Ident{{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: "C." + name,
|
|
||||||
Obj: obj,
|
|
||||||
}},
|
|
||||||
Type: typeExpr,
|
|
||||||
}
|
|
||||||
obj.Decl = valueSpec
|
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
|
||||||
return gen, nil
|
|
||||||
case C.CXCursor_MacroDefinition:
|
case C.CXCursor_MacroDefinition:
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
|
}
|
||||||
sourceRange := C.tinygo_clang_getCursorExtent(c)
|
sourceRange := C.tinygo_clang_getCursorExtent(c)
|
||||||
start := C.clang_getRangeStart(sourceRange)
|
start := C.clang_getRangeStart(sourceRange)
|
||||||
end := C.clang_getRangeEnd(sourceRange)
|
end := C.clang_getRangeEnd(sourceRange)
|
||||||
@@ -375,17 +242,17 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
|||||||
var startOffset, endOffset C.unsigned
|
var startOffset, endOffset C.unsigned
|
||||||
C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset)
|
C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset)
|
||||||
if file == nil {
|
if file == nil {
|
||||||
f.addError(pos, "internal error: could not find file where macro is defined")
|
p.addError(pos, "internal error: could not find file where macro is defined")
|
||||||
return nil, nil
|
break
|
||||||
}
|
}
|
||||||
C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset)
|
C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset)
|
||||||
if file != endFile {
|
if file != endFile {
|
||||||
f.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
|
p.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
|
||||||
return nil, nil
|
break
|
||||||
}
|
}
|
||||||
if startOffset > endOffset {
|
if startOffset > endOffset {
|
||||||
f.addError(pos, "internal error: start offset of macro is after end offset")
|
p.addError(pos, "internal error: start offset of macro is after end offset")
|
||||||
return nil, nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// read file contents and extract the relevant byte range
|
// read file contents and extract the relevant byte range
|
||||||
@@ -393,94 +260,31 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
|||||||
var size C.size_t
|
var size C.size_t
|
||||||
sourcePtr := C.clang_getFileContents(tu, file, &size)
|
sourcePtr := C.clang_getFileContents(tu, file, &size)
|
||||||
if endOffset >= C.uint(size) {
|
if endOffset >= C.uint(size) {
|
||||||
f.addError(pos, "internal error: end offset of macro lies after end of file")
|
p.addError(pos, "internal error: end offset of macro lies after end of file")
|
||||||
return nil, nil
|
break
|
||||||
}
|
}
|
||||||
source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset])
|
source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset])
|
||||||
if !strings.HasPrefix(source, name) {
|
if !strings.HasPrefix(source, name) {
|
||||||
f.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
|
p.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
|
||||||
return nil, nil
|
break
|
||||||
}
|
}
|
||||||
value := source[len(name):]
|
value := source[len(name):]
|
||||||
// Try to convert this #define into a Go constant expression.
|
// Try to convert this #define into a Go constant expression.
|
||||||
expr, scannerError := parseConst(pos+token.Pos(len(name)), f.fset, value)
|
expr, scannerError := parseConst(pos+token.Pos(len(name)), p.fset, value)
|
||||||
if scannerError != nil {
|
if scannerError != nil {
|
||||||
f.errors = append(f.errors, *scannerError)
|
p.errors = append(p.errors, *scannerError)
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
if expr != nil {
|
||||||
gen := &ast.GenDecl{
|
// Parsing was successful.
|
||||||
TokPos: token.NoPos,
|
p.constants[name] = constantInfo{expr, pos}
|
||||||
Tok: token.CONST,
|
|
||||||
Lparen: token.NoPos,
|
|
||||||
Rparen: token.NoPos,
|
|
||||||
}
|
}
|
||||||
obj := &ast.Object{
|
|
||||||
Kind: ast.Con,
|
|
||||||
Name: "C." + name,
|
|
||||||
}
|
|
||||||
valueSpec := &ast.ValueSpec{
|
|
||||||
Names: []*ast.Ident{{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: "C." + name,
|
|
||||||
Obj: obj,
|
|
||||||
}},
|
|
||||||
Values: []ast.Expr{expr},
|
|
||||||
}
|
|
||||||
obj.Decl = valueSpec
|
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
|
||||||
return gen, nil
|
|
||||||
case C.CXCursor_EnumDecl:
|
case C.CXCursor_EnumDecl:
|
||||||
obj := &ast.Object{
|
// Visit all enums, because the fields may be used even when the enum
|
||||||
Kind: ast.Typ,
|
// type itself is not.
|
||||||
Name: "C." + name,
|
typ := C.tinygo_clang_getCursorType(c)
|
||||||
}
|
p.makeASTType(typ, pos)
|
||||||
underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
|
|
||||||
// TODO: gc's CGo implementation uses types such as `uint32` for enums
|
|
||||||
// instead of types such as C.int, which are used here.
|
|
||||||
typeSpec := &ast.TypeSpec{
|
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: "C." + name,
|
|
||||||
Obj: obj,
|
|
||||||
},
|
|
||||||
Assign: pos,
|
|
||||||
Type: f.makeASTType(underlying, pos),
|
|
||||||
}
|
|
||||||
obj.Decl = typeSpec
|
|
||||||
return typeSpec, nil
|
|
||||||
case C.CXCursor_EnumConstantDecl:
|
|
||||||
value := C.tinygo_clang_getEnumConstantDeclValue(c)
|
|
||||||
expr := &ast.BasicLit{
|
|
||||||
ValuePos: pos,
|
|
||||||
Kind: token.INT,
|
|
||||||
Value: strconv.FormatInt(int64(value), 10),
|
|
||||||
}
|
|
||||||
gen := &ast.GenDecl{
|
|
||||||
TokPos: token.NoPos,
|
|
||||||
Tok: token.CONST,
|
|
||||||
Lparen: token.NoPos,
|
|
||||||
Rparen: token.NoPos,
|
|
||||||
}
|
|
||||||
obj := &ast.Object{
|
|
||||||
Kind: ast.Con,
|
|
||||||
Name: "C." + name,
|
|
||||||
}
|
|
||||||
valueSpec := &ast.ValueSpec{
|
|
||||||
Names: []*ast.Ident{{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: "C." + name,
|
|
||||||
Obj: obj,
|
|
||||||
}},
|
|
||||||
Values: []ast.Expr{expr},
|
|
||||||
}
|
|
||||||
obj.Decl = valueSpec
|
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
|
||||||
return gen, nil
|
|
||||||
default:
|
|
||||||
f.addError(pos, fmt.Sprintf("internal error: unknown cursor type: %d", kind))
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
func getString(clangString C.CXString) (s string) {
|
func getString(clangString C.CXString) (s string) {
|
||||||
@@ -490,49 +294,6 @@ func getString(clangString C.CXString) (s string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tinygo_clang_globals_visitor
|
|
||||||
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
|
||||||
f := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoFile)
|
|
||||||
switch C.tinygo_clang_getCursorKind(c) {
|
|
||||||
case C.CXCursor_FunctionDecl:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
f.names[name] = c
|
|
||||||
case C.CXCursor_StructDecl:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
if name != "" {
|
|
||||||
f.names["struct_"+name] = c
|
|
||||||
}
|
|
||||||
case C.CXCursor_UnionDecl:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
if name != "" {
|
|
||||||
f.names["union_"+name] = c
|
|
||||||
}
|
|
||||||
case C.CXCursor_TypedefDecl:
|
|
||||||
typedefType := C.tinygo_clang_getCursorType(c)
|
|
||||||
name := getString(C.clang_getTypedefName(typedefType))
|
|
||||||
f.names[name] = c
|
|
||||||
case C.CXCursor_VarDecl:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
f.names[name] = c
|
|
||||||
case C.CXCursor_MacroDefinition:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
f.names[name] = c
|
|
||||||
case C.CXCursor_EnumDecl:
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
if name != "" {
|
|
||||||
// Named enum, which can be referenced from Go using C.enum_foo.
|
|
||||||
f.names["enum_"+name] = c
|
|
||||||
}
|
|
||||||
// The enum fields are in global scope, so recurse to visit them.
|
|
||||||
return C.CXChildVisit_Recurse
|
|
||||||
case C.CXCursor_EnumConstantDecl:
|
|
||||||
// We arrive here because of the "Recurse" above.
|
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
|
||||||
f.names[name] = c
|
|
||||||
}
|
|
||||||
return C.CXChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCursorPosition returns a usable token.Pos from a libclang cursor.
|
// getCursorPosition returns a usable token.Pos from a libclang cursor.
|
||||||
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
||||||
return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor))
|
return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor))
|
||||||
@@ -630,7 +391,7 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
|
|||||||
// makeDecayingASTType does the same as makeASTType but takes care of decaying
|
// makeDecayingASTType does the same as makeASTType but takes care of decaying
|
||||||
// types (arrays in function parameters, etc). It is otherwise identical to
|
// types (arrays in function parameters, etc). It is otherwise identical to
|
||||||
// makeASTType.
|
// makeASTType.
|
||||||
func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
func (p *cgoPackage) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
// Strip typedefs, if any.
|
// Strip typedefs, if any.
|
||||||
underlyingType := typ
|
underlyingType := typ
|
||||||
if underlyingType.kind == C.CXType_Typedef {
|
if underlyingType.kind == C.CXType_Typedef {
|
||||||
@@ -656,15 +417,15 @@ func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
pointeeType := C.clang_getElementType(underlyingType)
|
pointeeType := C.clang_getElementType(underlyingType)
|
||||||
return &ast.StarExpr{
|
return &ast.StarExpr{
|
||||||
Star: pos,
|
Star: pos,
|
||||||
X: f.makeASTType(pointeeType, pos),
|
X: p.makeASTType(pointeeType, pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f.makeASTType(typ, pos)
|
return p.makeASTType(typ, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeASTType return the ast.Expr for the given libclang type. In other words,
|
// makeASTType return the ast.Expr for the given libclang type. In other words,
|
||||||
// it converts a libclang type to a type in the Go AST.
|
// it converts a libclang type to a type in the Go AST.
|
||||||
func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
var typeName string
|
var typeName string
|
||||||
switch typ.kind {
|
switch typ.kind {
|
||||||
case C.CXType_Char_S, C.CXType_Char_U:
|
case C.CXType_Char_S, C.CXType_Char_U:
|
||||||
@@ -725,7 +486,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
}
|
}
|
||||||
return &ast.StarExpr{
|
return &ast.StarExpr{
|
||||||
Star: pos,
|
Star: pos,
|
||||||
X: f.makeASTType(pointeeType, pos),
|
X: p.makeASTType(pointeeType, pos),
|
||||||
}
|
}
|
||||||
case C.CXType_ConstantArray:
|
case C.CXType_ConstantArray:
|
||||||
return &ast.ArrayType{
|
return &ast.ArrayType{
|
||||||
@@ -735,7 +496,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
Kind: token.INT,
|
Kind: token.INT,
|
||||||
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
|
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
|
||||||
},
|
},
|
||||||
Elt: f.makeASTType(C.clang_getElementType(typ), pos),
|
Elt: p.makeASTType(C.clang_getElementType(typ), pos),
|
||||||
}
|
}
|
||||||
case C.CXType_FunctionProto:
|
case C.CXType_FunctionProto:
|
||||||
// Be compatible with gc, which uses the *[0]byte type for function
|
// Be compatible with gc, which uses the *[0]byte type for function
|
||||||
@@ -756,21 +517,71 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
}
|
}
|
||||||
case C.CXType_Typedef:
|
case C.CXType_Typedef:
|
||||||
name := getString(C.clang_getTypedefName(typ))
|
name := getString(C.clang_getTypedefName(typ))
|
||||||
c := C.tinygo_clang_getTypeDeclaration(typ)
|
if _, ok := p.typedefs[name]; !ok {
|
||||||
|
p.typedefs[name] = nil // don't recurse
|
||||||
|
c := C.tinygo_clang_getTypeDeclaration(typ)
|
||||||
|
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
||||||
|
expr := p.makeASTType(underlyingType, pos)
|
||||||
|
if strings.HasPrefix(name, "_Cgo_") {
|
||||||
|
expr := expr.(*ast.Ident)
|
||||||
|
typeSize := C.clang_Type_getSizeOf(underlyingType)
|
||||||
|
switch expr.Name {
|
||||||
|
case "C.char":
|
||||||
|
if typeSize != 1 {
|
||||||
|
// This happens for some very special purpose architectures
|
||||||
|
// (DSPs etc.) that are not currently targeted.
|
||||||
|
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
|
||||||
|
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
|
||||||
|
}
|
||||||
|
switch underlyingType.kind {
|
||||||
|
case C.CXType_Char_S:
|
||||||
|
expr.Name = "int8"
|
||||||
|
case C.CXType_Char_U:
|
||||||
|
expr.Name = "uint8"
|
||||||
|
}
|
||||||
|
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
|
||||||
|
switch typeSize {
|
||||||
|
case 1:
|
||||||
|
expr.Name = "int8"
|
||||||
|
case 2:
|
||||||
|
expr.Name = "int16"
|
||||||
|
case 4:
|
||||||
|
expr.Name = "int32"
|
||||||
|
case 8:
|
||||||
|
expr.Name = "int64"
|
||||||
|
}
|
||||||
|
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
|
||||||
|
switch typeSize {
|
||||||
|
case 1:
|
||||||
|
expr.Name = "uint8"
|
||||||
|
case 2:
|
||||||
|
expr.Name = "uint16"
|
||||||
|
case 4:
|
||||||
|
expr.Name = "uint32"
|
||||||
|
case 8:
|
||||||
|
expr.Name = "uint64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.typedefs[name] = &typedefInfo{
|
||||||
|
typeExpr: expr,
|
||||||
|
pos: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
return &ast.Ident{
|
return &ast.Ident{
|
||||||
NamePos: pos,
|
NamePos: pos,
|
||||||
Name: f.getASTDeclName(name, c, false),
|
Name: "C." + name,
|
||||||
}
|
}
|
||||||
case C.CXType_Elaborated:
|
case C.CXType_Elaborated:
|
||||||
underlying := C.clang_Type_getNamedType(typ)
|
underlying := C.clang_Type_getNamedType(typ)
|
||||||
switch underlying.kind {
|
switch underlying.kind {
|
||||||
case C.CXType_Record:
|
case C.CXType_Record:
|
||||||
return f.makeASTType(underlying, pos)
|
return p.makeASTType(underlying, pos)
|
||||||
case C.CXType_Enum:
|
case C.CXType_Enum:
|
||||||
return f.makeASTType(underlying, pos)
|
return p.makeASTType(underlying, pos)
|
||||||
default:
|
default:
|
||||||
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
|
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
|
||||||
f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
|
p.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
|
||||||
typeName = "<unknown>"
|
typeName = "<unknown>"
|
||||||
}
|
}
|
||||||
case C.CXType_Record:
|
case C.CXType_Record:
|
||||||
@@ -788,46 +599,63 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
}
|
}
|
||||||
if name == "" {
|
if name == "" {
|
||||||
// Anonymous record, probably inside a typedef.
|
// Anonymous record, probably inside a typedef.
|
||||||
clangLocation := C.tinygo_clang_getCursorLocation(cursor)
|
typeInfo := p.makeASTRecordType(cursor, pos)
|
||||||
var file C.CXFile
|
if typeInfo.bitfields != nil || typeInfo.unionSize != 0 {
|
||||||
var line C.unsigned
|
// This record is a union or is a struct with bitfields, so we
|
||||||
var column C.unsigned
|
// have to declare it as a named type (for getters/setters to
|
||||||
C.clang_getFileLocation(clangLocation, &file, &line, &column, nil)
|
// work).
|
||||||
location := token.Position{
|
p.anonStructNum++
|
||||||
Filename: getString(C.clang_getFileName(file)),
|
cgoName := cgoRecordPrefix + strconv.Itoa(p.anonStructNum)
|
||||||
Line: int(line),
|
p.elaboratedTypes[cgoName] = typeInfo
|
||||||
Column: int(column),
|
return &ast.Ident{
|
||||||
|
NamePos: pos,
|
||||||
|
Name: "C." + cgoName,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if location.Filename == "" || location.Line == 0 {
|
return typeInfo.typeExpr
|
||||||
// Not sure when this would happen, but protect from it anyway.
|
|
||||||
f.addError(pos, "could not find file/line information")
|
|
||||||
}
|
|
||||||
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
|
|
||||||
} else {
|
} else {
|
||||||
name = cgoRecordPrefix + name
|
cgoName := cgoRecordPrefix + name
|
||||||
}
|
if _, ok := p.elaboratedTypes[cgoName]; !ok {
|
||||||
return &ast.Ident{
|
p.elaboratedTypes[cgoName] = nil // predeclare (to avoid endless recursion)
|
||||||
NamePos: pos,
|
p.elaboratedTypes[cgoName] = p.makeASTRecordType(cursor, pos)
|
||||||
Name: f.getASTDeclName(name, cursor, false),
|
}
|
||||||
|
return &ast.Ident{
|
||||||
|
NamePos: pos,
|
||||||
|
Name: "C." + cgoName,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case C.CXType_Enum:
|
case C.CXType_Enum:
|
||||||
cursor := C.tinygo_clang_getTypeDeclaration(typ)
|
cursor := C.tinygo_clang_getTypeDeclaration(typ)
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(cursor))
|
name := getString(C.tinygo_clang_getCursorSpelling(cursor))
|
||||||
|
underlying := C.tinygo_clang_getEnumDeclIntegerType(cursor)
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = f.getUnnamedDeclName("_Ctype_enum___", cursor)
|
// anonymous enum
|
||||||
|
ref := storedRefs.Put(p)
|
||||||
|
defer storedRefs.Remove(ref)
|
||||||
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
|
||||||
|
return p.makeASTType(underlying, pos)
|
||||||
} else {
|
} else {
|
||||||
name = "enum_" + name
|
// named enum
|
||||||
}
|
if _, ok := p.enums[name]; !ok {
|
||||||
return &ast.Ident{
|
ref := storedRefs.Put(p)
|
||||||
NamePos: pos,
|
defer storedRefs.Remove(ref)
|
||||||
Name: f.getASTDeclName(name, cursor, false),
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
|
||||||
|
p.enums[name] = enumInfo{
|
||||||
|
typeExpr: p.makeASTType(underlying, pos),
|
||||||
|
pos: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ast.Ident{
|
||||||
|
NamePos: pos,
|
||||||
|
Name: "C.enum_" + name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if typeName == "" {
|
if typeName == "" {
|
||||||
// Report this as an error.
|
// Report this as an error.
|
||||||
typeSpelling := getString(C.clang_getTypeSpelling(typ))
|
typeSpelling := getString(C.clang_getTypeSpelling(typ))
|
||||||
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
|
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
|
||||||
f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
|
p.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
|
||||||
typeName = "C.<unknown>"
|
typeName = "C.<unknown>"
|
||||||
}
|
}
|
||||||
return &ast.Ident{
|
return &ast.Ident{
|
||||||
@@ -836,80 +664,9 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getIntegerType returns an AST node that defines types such as C.int.
|
|
||||||
func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSpec {
|
|
||||||
pos := p.getCursorPosition(cursor)
|
|
||||||
|
|
||||||
// Find a Go type that matches the size and signedness of the given C type.
|
|
||||||
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(cursor)
|
|
||||||
var goName string
|
|
||||||
typeSize := C.clang_Type_getSizeOf(underlyingType)
|
|
||||||
switch name {
|
|
||||||
case "C.char":
|
|
||||||
if typeSize != 1 {
|
|
||||||
// This happens for some very special purpose architectures
|
|
||||||
// (DSPs etc.) that are not currently targeted.
|
|
||||||
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
|
|
||||||
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
|
|
||||||
}
|
|
||||||
switch underlyingType.kind {
|
|
||||||
case C.CXType_Char_S:
|
|
||||||
goName = "int8"
|
|
||||||
case C.CXType_Char_U:
|
|
||||||
goName = "uint8"
|
|
||||||
}
|
|
||||||
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
|
|
||||||
switch typeSize {
|
|
||||||
case 1:
|
|
||||||
goName = "int8"
|
|
||||||
case 2:
|
|
||||||
goName = "int16"
|
|
||||||
case 4:
|
|
||||||
goName = "int32"
|
|
||||||
case 8:
|
|
||||||
goName = "int64"
|
|
||||||
}
|
|
||||||
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
|
|
||||||
switch typeSize {
|
|
||||||
case 1:
|
|
||||||
goName = "uint8"
|
|
||||||
case 2:
|
|
||||||
goName = "uint16"
|
|
||||||
case 4:
|
|
||||||
goName = "uint32"
|
|
||||||
case 8:
|
|
||||||
goName = "uint64"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if goName == "" { // should not happen
|
|
||||||
p.addError(pos, "internal error: did not find Go type for C type "+name)
|
|
||||||
goName = "int"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct an *ast.TypeSpec for this type.
|
|
||||||
obj := &ast.Object{
|
|
||||||
Kind: ast.Typ,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
spec := &ast.TypeSpec{
|
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: name,
|
|
||||||
Obj: obj,
|
|
||||||
},
|
|
||||||
Type: &ast.Ident{
|
|
||||||
NamePos: pos,
|
|
||||||
Name: goName,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
obj.Decl = spec
|
|
||||||
return spec
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeASTRecordType parses a C record (struct or union) and translates it into
|
// makeASTRecordType parses a C record (struct or union) and translates it into
|
||||||
// a Go struct type.
|
// a Go struct type.
|
||||||
func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
|
func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
|
||||||
fieldList := &ast.FieldList{
|
fieldList := &ast.FieldList{
|
||||||
Opening: pos,
|
Opening: pos,
|
||||||
Closing: pos,
|
Closing: pos,
|
||||||
@@ -919,11 +676,11 @@ func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elabora
|
|||||||
bitfieldNum := 0
|
bitfieldNum := 0
|
||||||
ref := storedRefs.Put(struct {
|
ref := storedRefs.Put(struct {
|
||||||
fieldList *ast.FieldList
|
fieldList *ast.FieldList
|
||||||
file *cgoFile
|
pkg *cgoPackage
|
||||||
inBitfield *bool
|
inBitfield *bool
|
||||||
bitfieldNum *int
|
bitfieldNum *int
|
||||||
bitfieldList *[]bitfieldInfo
|
bitfieldList *[]bitfieldInfo
|
||||||
}{fieldList, f, &inBitfield, &bitfieldNum, &bitfieldList})
|
}{fieldList, p, &inBitfield, &bitfieldNum, &bitfieldList})
|
||||||
defer storedRefs.Remove(ref)
|
defer storedRefs.Remove(ref)
|
||||||
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
|
||||||
renameFieldKeywords(fieldList)
|
renameFieldKeywords(fieldList)
|
||||||
@@ -952,13 +709,13 @@ func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elabora
|
|||||||
}
|
}
|
||||||
if bitfieldList != nil {
|
if bitfieldList != nil {
|
||||||
// This is valid C... but please don't do this.
|
// This is valid C... but please don't do this.
|
||||||
f.addError(pos, "bitfield in a union is not supported")
|
p.addError(pos, "bitfield in a union is not supported")
|
||||||
}
|
}
|
||||||
typ := C.tinygo_clang_getCursorType(cursor)
|
typ := C.tinygo_clang_getCursorType(cursor)
|
||||||
alignInBytes := int64(C.clang_Type_getAlignOf(typ))
|
alignInBytes := int64(C.clang_Type_getAlignOf(typ))
|
||||||
sizeInBytes := int64(C.clang_Type_getSizeOf(typ))
|
sizeInBytes := int64(C.clang_Type_getSizeOf(typ))
|
||||||
if sizeInBytes == 0 {
|
if sizeInBytes == 0 {
|
||||||
f.addError(pos, "zero-length union is not supported")
|
p.addError(pos, "zero-length union is not supported")
|
||||||
}
|
}
|
||||||
typeInfo.unionSize = sizeInBytes
|
typeInfo.unionSize = sizeInBytes
|
||||||
typeInfo.unionAlign = alignInBytes
|
typeInfo.unionAlign = alignInBytes
|
||||||
@@ -966,7 +723,7 @@ func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elabora
|
|||||||
default:
|
default:
|
||||||
cursorKind := C.tinygo_clang_getCursorKind(cursor)
|
cursorKind := C.tinygo_clang_getCursorKind(cursor)
|
||||||
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
|
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
|
||||||
f.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
|
p.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
|
||||||
return &elaboratedTypeInfo{
|
return &elaboratedTypeInfo{
|
||||||
typeExpr: &ast.StructType{
|
typeExpr: &ast.StructType{
|
||||||
Struct: pos,
|
Struct: pos,
|
||||||
@@ -980,17 +737,17 @@ func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elabora
|
|||||||
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
|
passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
|
||||||
fieldList *ast.FieldList
|
fieldList *ast.FieldList
|
||||||
file *cgoFile
|
pkg *cgoPackage
|
||||||
inBitfield *bool
|
inBitfield *bool
|
||||||
bitfieldNum *int
|
bitfieldNum *int
|
||||||
bitfieldList *[]bitfieldInfo
|
bitfieldList *[]bitfieldInfo
|
||||||
})
|
})
|
||||||
fieldList := passed.fieldList
|
fieldList := passed.fieldList
|
||||||
f := passed.file
|
p := passed.pkg
|
||||||
inBitfield := passed.inBitfield
|
inBitfield := passed.inBitfield
|
||||||
bitfieldNum := passed.bitfieldNum
|
bitfieldNum := passed.bitfieldNum
|
||||||
bitfieldList := passed.bitfieldList
|
bitfieldList := passed.bitfieldList
|
||||||
pos := f.getCursorPosition(c)
|
pos := p.getCursorPosition(c)
|
||||||
switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind {
|
switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind {
|
||||||
case C.CXCursor_FieldDecl:
|
case C.CXCursor_FieldDecl:
|
||||||
// Expected. This is a regular field.
|
// Expected. This is a regular field.
|
||||||
@@ -999,7 +756,7 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
|||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
default:
|
default:
|
||||||
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
|
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
|
||||||
f.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
|
p.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
@@ -1010,14 +767,14 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
|||||||
}
|
}
|
||||||
typ := C.tinygo_clang_getCursorType(c)
|
typ := C.tinygo_clang_getCursorType(c)
|
||||||
field := &ast.Field{
|
field := &ast.Field{
|
||||||
Type: f.makeASTType(typ, f.getCursorPosition(c)),
|
Type: p.makeASTType(typ, p.getCursorPosition(c)),
|
||||||
}
|
}
|
||||||
offsetof := int64(C.clang_Type_getOffsetOf(C.tinygo_clang_getCursorType(parent), C.CString(name)))
|
offsetof := int64(C.clang_Type_getOffsetOf(C.tinygo_clang_getCursorType(parent), C.CString(name)))
|
||||||
alignOf := int64(C.clang_Type_getAlignOf(typ) * 8)
|
alignOf := int64(C.clang_Type_getAlignOf(typ) * 8)
|
||||||
bitfieldOffset := offsetof % alignOf
|
bitfieldOffset := offsetof % alignOf
|
||||||
if bitfieldOffset != 0 {
|
if bitfieldOffset != 0 {
|
||||||
if C.tinygo_clang_Cursor_isBitField(c) != 1 {
|
if C.tinygo_clang_Cursor_isBitField(c) != 1 {
|
||||||
f.addError(pos, "expected a bitfield")
|
p.addError(pos, "expected a bitfield")
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
if !*inBitfield {
|
if !*inBitfield {
|
||||||
@@ -1064,6 +821,23 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
|||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export tinygo_clang_enum_visitor
|
||||||
|
func tinygo_clang_enum_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
|
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
|
pos := p.getCursorPosition(c)
|
||||||
|
value := C.tinygo_clang_getEnumConstantDeclValue(c)
|
||||||
|
p.constants[name] = constantInfo{
|
||||||
|
expr: &ast.BasicLit{
|
||||||
|
ValuePos: pos,
|
||||||
|
Kind: token.INT,
|
||||||
|
Value: strconv.FormatInt(int64(value), 10),
|
||||||
|
},
|
||||||
|
pos: pos,
|
||||||
|
}
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
|
}
|
||||||
|
|
||||||
//export tinygo_clang_inclusion_visitor
|
//export tinygo_clang_inclusion_visitor
|
||||||
func tinygo_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) {
|
func tinygo_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) {
|
||||||
callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile))
|
callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile))
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build !byollvm && llvm11
|
||||||
|
// +build !byollvm,llvm11
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
|
||||||
|
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
|
||||||
|
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
|
||||||
|
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
|
||||||
|
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
|
||||||
|
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build !byollvm && llvm12
|
||||||
|
// +build !byollvm,llvm12
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
|
||||||
|
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
|
||||||
|
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
|
||||||
|
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
|
||||||
|
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
|
||||||
|
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build !byollvm && !llvm11 && !llvm12
|
||||||
|
// +build !byollvm,!llvm11,!llvm12
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux CFLAGS: -I/usr/lib/llvm-13/include
|
||||||
|
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@13/include
|
||||||
|
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@13/include
|
||||||
|
#cgo freebsd CFLAGS: -I/usr/local/llvm13/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-13/lib -lclang
|
||||||
|
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@13/lib -lclang -lffi
|
||||||
|
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@13/lib -lclang -lffi
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/llvm13/lib -lclang
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//go:build !byollvm
|
|
||||||
// +build !byollvm
|
|
||||||
|
|
||||||
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"
|
|
||||||
+1
-13
@@ -3,7 +3,7 @@
|
|||||||
// are slightly different from the ones defined in libclang.go, but they
|
// are slightly different from the ones defined in libclang.go, but they
|
||||||
// should be ABI compatible.
|
// should be ABI compatible.
|
||||||
|
|
||||||
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
|
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
|
||||||
|
|
||||||
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
|
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
|
||||||
return clang_getTranslationUnitCursor(tu);
|
return clang_getTranslationUnitCursor(tu);
|
||||||
@@ -17,14 +17,6 @@ CXString tinygo_clang_getCursorSpelling(CXCursor c) {
|
|||||||
return clang_getCursorSpelling(c);
|
return clang_getCursorSpelling(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
CXString tinygo_clang_getCursorPrettyPrinted(CXCursor c, CXPrintingPolicy policy) {
|
|
||||||
return clang_getCursorPrettyPrinted(c, policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(CXCursor c) {
|
|
||||||
return clang_getCursorPrintingPolicy(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
|
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
|
||||||
return clang_getCursorKind(c);
|
return clang_getCursorKind(c);
|
||||||
}
|
}
|
||||||
@@ -53,10 +45,6 @@ CXCursor tinygo_clang_Cursor_getArgument(CXCursor c, unsigned i) {
|
|||||||
return clang_Cursor_getArgument(c, i);
|
return clang_Cursor_getArgument(c, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(CXCursor c) {
|
|
||||||
return clang_Cursor_getStorageClass(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
|
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
|
||||||
return clang_getCursorLocation(c);
|
return clang_getCursorLocation(c);
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+20
-13
@@ -24,16 +24,23 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type C.int16_t = int16
|
||||||
C.char uint8
|
type C.int32_t = int32
|
||||||
C.schar int8
|
type C.int64_t = int64
|
||||||
C.uchar uint8
|
type C.int8_t = int8
|
||||||
C.short int16
|
type C.uint16_t = uint16
|
||||||
C.ushort uint16
|
type C.uint32_t = uint32
|
||||||
C.int int32
|
type C.uint64_t = uint64
|
||||||
C.uint uint32
|
type C.uint8_t = uint8
|
||||||
C.long int32
|
type C.uintptr_t = uintptr
|
||||||
C.ulong uint32
|
type C.char uint8
|
||||||
C.longlong int64
|
type C.int int32
|
||||||
C.ulonglong uint64
|
type C.long int32
|
||||||
)
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
|||||||
Vendored
+22
-15
@@ -24,19 +24,26 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
C.char uint8
|
|
||||||
C.schar int8
|
|
||||||
C.uchar uint8
|
|
||||||
C.short int16
|
|
||||||
C.ushort uint16
|
|
||||||
C.int int32
|
|
||||||
C.uint uint32
|
|
||||||
C.long int32
|
|
||||||
C.ulong uint32
|
|
||||||
C.longlong int64
|
|
||||||
C.ulonglong uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
const C.foo = 3
|
|
||||||
const C.bar = C.foo
|
const C.bar = C.foo
|
||||||
|
const C.foo = 3
|
||||||
|
|
||||||
|
type C.int16_t = int16
|
||||||
|
type C.int32_t = int32
|
||||||
|
type C.int64_t = int64
|
||||||
|
type C.int8_t = int8
|
||||||
|
type C.uint16_t = uint16
|
||||||
|
type C.uint32_t = uint32
|
||||||
|
type C.uint64_t = uint64
|
||||||
|
type C.uint8_t = uint8
|
||||||
|
type C.uintptr_t = uintptr
|
||||||
|
type C.char uint8
|
||||||
|
type C.int int32
|
||||||
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
|||||||
Vendored
+1
-1
@@ -27,7 +27,7 @@ import "C"
|
|||||||
//line errors.go:100
|
//line errors.go:100
|
||||||
var (
|
var (
|
||||||
// constant too large
|
// constant too large
|
||||||
_ C.char = 2 << 10
|
_ C.uint8_t = 2 << 10
|
||||||
|
|
||||||
// z member does not exist
|
// z member does not exist
|
||||||
_ C.point_t = C.point_t{z: 3}
|
_ C.point_t = C.point_t{z: 3}
|
||||||
|
|||||||
Vendored
+24
-18
@@ -6,7 +6,7 @@
|
|||||||
// testdata/errors.go:19:26: unexpected token ), expected end of expression
|
// testdata/errors.go:19:26: unexpected token ), expected end of expression
|
||||||
|
|
||||||
// Type checking errors after CGo processing:
|
// Type checking errors after CGo processing:
|
||||||
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
|
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as uint8 value in variable declaration (overflows)
|
||||||
// testdata/errors.go:105: unknown field z in struct literal
|
// testdata/errors.go:105: unknown field z in struct literal
|
||||||
// testdata/errors.go:108: undeclared name: C.SOME_CONST_1
|
// testdata/errors.go:108: undeclared name: C.SOME_CONST_1
|
||||||
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
|
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
|
||||||
@@ -38,23 +38,29 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
const C.SOME_CONST_3 = 1234
|
||||||
C.char uint8
|
|
||||||
C.schar int8
|
type C.int16_t = int16
|
||||||
C.uchar uint8
|
type C.int32_t = int32
|
||||||
C.short int16
|
type C.int64_t = int64
|
||||||
C.ushort uint16
|
type C.int8_t = int8
|
||||||
C.int int32
|
type C.uint16_t = uint16
|
||||||
C.uint uint32
|
type C.uint32_t = uint32
|
||||||
C.long int32
|
type C.uint64_t = uint64
|
||||||
C.ulong uint32
|
type C.uint8_t = uint8
|
||||||
C.longlong int64
|
type C.uintptr_t = uintptr
|
||||||
C.ulonglong uint64
|
type C.char uint8
|
||||||
)
|
type C.int int32
|
||||||
type C._Ctype_struct___0 struct {
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
type C.point_t = struct {
|
||||||
x C.int
|
x C.int
|
||||||
y C.int
|
y C.int
|
||||||
}
|
}
|
||||||
type C.point_t = C._Ctype_struct___0
|
|
||||||
|
|
||||||
const C.SOME_CONST_3 = 1234
|
|
||||||
|
|||||||
Vendored
+21
-14
@@ -29,19 +29,26 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
C.char uint8
|
|
||||||
C.schar int8
|
|
||||||
C.uchar uint8
|
|
||||||
C.short int16
|
|
||||||
C.ushort uint16
|
|
||||||
C.int int32
|
|
||||||
C.uint uint32
|
|
||||||
C.long int32
|
|
||||||
C.ulong uint32
|
|
||||||
C.longlong int64
|
|
||||||
C.ulonglong uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
const C.BAR = 3
|
const C.BAR = 3
|
||||||
const C.FOO_H = 1
|
const C.FOO_H = 1
|
||||||
|
|
||||||
|
type C.int16_t = int16
|
||||||
|
type C.int32_t = int32
|
||||||
|
type C.int64_t = int64
|
||||||
|
type C.int8_t = int8
|
||||||
|
type C.uint16_t = uint16
|
||||||
|
type C.uint32_t = uint32
|
||||||
|
type C.uint64_t = uint64
|
||||||
|
type C.uint8_t = uint8
|
||||||
|
type C.uintptr_t = uintptr
|
||||||
|
type C.char uint8
|
||||||
|
type C.int int32
|
||||||
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
|||||||
Vendored
-2
@@ -5,7 +5,6 @@ package main
|
|||||||
int foo(int a, int b);
|
int foo(int a, int b);
|
||||||
void variadic0();
|
void variadic0();
|
||||||
void variadic2(int x, int y, ...);
|
void variadic2(int x, int y, ...);
|
||||||
static void staticfunc(int x);
|
|
||||||
|
|
||||||
// Global variable signatures.
|
// Global variable signatures.
|
||||||
extern int someValue;
|
extern int someValue;
|
||||||
@@ -17,7 +16,6 @@ func accessFunctions() {
|
|||||||
C.foo(3, 4)
|
C.foo(3, 4)
|
||||||
C.variadic0()
|
C.variadic0()
|
||||||
C.variadic2(3, 5)
|
C.variadic2(3, 5)
|
||||||
C.staticfunc(3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func accessGlobals() {
|
func accessGlobals() {
|
||||||
|
|||||||
Vendored
+23
-23
@@ -24,41 +24,41 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
C.char uint8
|
|
||||||
C.schar int8
|
|
||||||
C.uchar uint8
|
|
||||||
C.short int16
|
|
||||||
C.ushort uint16
|
|
||||||
C.int int32
|
|
||||||
C.uint uint32
|
|
||||||
C.long int32
|
|
||||||
C.ulong uint32
|
|
||||||
C.longlong int64
|
|
||||||
C.ulonglong uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
//export foo
|
//export foo
|
||||||
func C.foo(a C.int, b C.int) C.int
|
func C.foo(a C.int, b C.int) C.int
|
||||||
|
|
||||||
var C.foo$funcaddr unsafe.Pointer
|
|
||||||
|
|
||||||
//export variadic0
|
//export variadic0
|
||||||
//go:variadic
|
//go:variadic
|
||||||
func C.variadic0()
|
func C.variadic0()
|
||||||
|
|
||||||
var C.variadic0$funcaddr unsafe.Pointer
|
|
||||||
|
|
||||||
//export variadic2
|
//export variadic2
|
||||||
//go:variadic
|
//go:variadic
|
||||||
func C.variadic2(x C.int, y C.int)
|
func C.variadic2(x C.int, y C.int)
|
||||||
|
|
||||||
|
var C.foo$funcaddr unsafe.Pointer
|
||||||
|
var C.variadic0$funcaddr unsafe.Pointer
|
||||||
var C.variadic2$funcaddr unsafe.Pointer
|
var C.variadic2$funcaddr unsafe.Pointer
|
||||||
|
|
||||||
//export _Cgo_static_173c95a79b6df1980521_staticfunc
|
|
||||||
func C.staticfunc!symbols.go(x C.int)
|
|
||||||
|
|
||||||
var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
|
|
||||||
|
|
||||||
//go:extern someValue
|
//go:extern someValue
|
||||||
var C.someValue C.int
|
var C.someValue C.int
|
||||||
|
|
||||||
|
type C.int16_t = int16
|
||||||
|
type C.int32_t = int32
|
||||||
|
type C.int64_t = int64
|
||||||
|
type C.int8_t = int8
|
||||||
|
type C.uint16_t = uint16
|
||||||
|
type C.uint32_t = uint32
|
||||||
|
type C.uint64_t = uint64
|
||||||
|
type C.uint8_t = uint8
|
||||||
|
type C.uintptr_t = uintptr
|
||||||
|
type C.char uint8
|
||||||
|
type C.int int32
|
||||||
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
|||||||
Vendored
+106
-100
@@ -24,126 +24,132 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
return C.__GoBytes(ptr, uintptr(length))
|
return C.__GoBytes(ptr, uintptr(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
const C.option2A = 20
|
||||||
C.char uint8
|
const C.optionA = 0
|
||||||
C.schar int8
|
const C.optionB = 1
|
||||||
C.uchar uint8
|
const C.optionC = -5
|
||||||
C.short int16
|
const C.optionD = -4
|
||||||
C.ushort uint16
|
const C.optionE = 10
|
||||||
C.int int32
|
const C.optionF = 11
|
||||||
C.uint uint32
|
const C.optionG = 12
|
||||||
C.long int32
|
const C.unused1 = 5
|
||||||
C.ulong uint32
|
|
||||||
C.longlong int64
|
type C.int16_t = int16
|
||||||
C.ulonglong uint64
|
type C.int32_t = int32
|
||||||
)
|
type C.int64_t = int64
|
||||||
|
type C.int8_t = int8
|
||||||
|
type C.uint16_t = uint16
|
||||||
|
type C.uint32_t = uint32
|
||||||
|
type C.uint64_t = uint64
|
||||||
|
type C.uint8_t = uint8
|
||||||
|
type C.uintptr_t = uintptr
|
||||||
|
type C.char uint8
|
||||||
|
type C.int int32
|
||||||
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
||||||
|
type C.bitfield_t = C.struct_4
|
||||||
|
type C.myIntArray = [10]C.int
|
||||||
type C.myint = C.int
|
type C.myint = C.int
|
||||||
type C._Ctype_struct___0 struct {
|
type C.option2_t = C.uint
|
||||||
|
type C.option_t = C.enum_option
|
||||||
|
type C.point2d_t = struct {
|
||||||
x C.int
|
x C.int
|
||||||
y C.int
|
y C.int
|
||||||
}
|
}
|
||||||
type C.point2d_t = C._Ctype_struct___0
|
|
||||||
type C.struct_point3d struct {
|
|
||||||
x C.int
|
|
||||||
y C.int
|
|
||||||
z C.int
|
|
||||||
}
|
|
||||||
type C.point3d_t = C.struct_point3d
|
type C.point3d_t = C.struct_point3d
|
||||||
type C.struct_type1 struct {
|
type C.struct_nested_t = struct {
|
||||||
_type C.int
|
|
||||||
__type C.int
|
|
||||||
___type C.int
|
|
||||||
}
|
|
||||||
type C.struct_type2 struct{ _type C.int }
|
|
||||||
type C._Ctype_union___1 struct{ i C.int }
|
|
||||||
type C.union1_t = C._Ctype_union___1
|
|
||||||
type C._Ctype_union___2 struct{ $union uint64 }
|
|
||||||
|
|
||||||
func (union *C._Ctype_union___2) unionfield_i() *C.int {
|
|
||||||
return (*C.int)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
func (union *C._Ctype_union___2) unionfield_d() *float64 {
|
|
||||||
return (*float64)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
func (union *C._Ctype_union___2) unionfield_s() *C.short {
|
|
||||||
return (*C.short)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
|
|
||||||
type C.union3_t = C._Ctype_union___2
|
|
||||||
type C.union_union2d struct{ $union [2]uint64 }
|
|
||||||
|
|
||||||
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
|
|
||||||
func (union *C.union_union2d) unionfield_d() *[2]float64 {
|
|
||||||
return (*[2]float64)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
|
|
||||||
type C.union2d_t = C.union_union2d
|
|
||||||
type C._Ctype_union___3 struct{ arr [10]C.uchar }
|
|
||||||
type C.unionarray_t = C._Ctype_union___3
|
|
||||||
type C._Ctype_union___5 struct{ $union [3]uint32 }
|
|
||||||
|
|
||||||
func (union *C._Ctype_union___5) unionfield_area() *C.point2d_t {
|
|
||||||
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
func (union *C._Ctype_union___5) unionfield_solid() *C.point3d_t {
|
|
||||||
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
|
|
||||||
type C._Ctype_struct___4 struct {
|
|
||||||
begin C.point2d_t
|
begin C.point2d_t
|
||||||
end C.point2d_t
|
end C.point2d_t
|
||||||
tag C.int
|
tag C.int
|
||||||
|
|
||||||
coord C._Ctype_union___5
|
coord C.union_2
|
||||||
}
|
}
|
||||||
type C.struct_nested_t = C._Ctype_struct___4
|
type C.types_t = struct {
|
||||||
type C._Ctype_union___6 struct{ $union [2]uint64 }
|
|
||||||
|
|
||||||
func (union *C._Ctype_union___6) unionfield_point() *C.point3d_t {
|
|
||||||
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
func (union *C._Ctype_union___6) unionfield_array() *C.unionarray_t {
|
|
||||||
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
func (union *C._Ctype_union___6) unionfield_thing() *C.union3_t {
|
|
||||||
return (*C.union3_t)(unsafe.Pointer(&union.$union))
|
|
||||||
}
|
|
||||||
|
|
||||||
type C.union_nested_t = C._Ctype_union___6
|
|
||||||
type C.enum_option = C.int
|
|
||||||
type C.option_t = C.enum_option
|
|
||||||
type C._Ctype_enum___7 = C.uint
|
|
||||||
type C.option2_t = C._Ctype_enum___7
|
|
||||||
type C._Ctype_struct___8 struct {
|
|
||||||
f float32
|
f float32
|
||||||
d float64
|
d float64
|
||||||
ptr *C.int
|
ptr *C.int
|
||||||
}
|
}
|
||||||
type C.types_t = C._Ctype_struct___8
|
type C.union1_t = struct{ i C.int }
|
||||||
type C.myIntArray = [10]C.int
|
type C.union2d_t = C.union_union2d
|
||||||
type C._Ctype_struct___9 struct {
|
type C.union3_t = C.union_1
|
||||||
|
type C.union_nested_t = C.union_3
|
||||||
|
type C.unionarray_t = struct{ arr [10]C.uchar }
|
||||||
|
|
||||||
|
func (s *C.struct_4) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
|
||||||
|
func (s *C.struct_4) set_bitfield_a(value C.uchar) {
|
||||||
|
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
|
||||||
|
}
|
||||||
|
func (s *C.struct_4) bitfield_b() C.uchar {
|
||||||
|
return s.__bitfield_1 >> 5 & 0x1
|
||||||
|
}
|
||||||
|
func (s *C.struct_4) set_bitfield_b(value C.uchar) {
|
||||||
|
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
|
||||||
|
}
|
||||||
|
func (s *C.struct_4) bitfield_c() C.uchar {
|
||||||
|
return s.__bitfield_1 >> 6
|
||||||
|
}
|
||||||
|
func (s *C.struct_4) set_bitfield_c(value C.uchar,
|
||||||
|
|
||||||
|
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
|
||||||
|
|
||||||
|
type C.struct_4 struct {
|
||||||
start C.uchar
|
start C.uchar
|
||||||
__bitfield_1 C.uchar
|
__bitfield_1 C.uchar
|
||||||
|
|
||||||
d C.uchar
|
d C.uchar
|
||||||
e C.uchar
|
e C.uchar
|
||||||
}
|
}
|
||||||
|
type C.struct_point3d struct {
|
||||||
|
x C.int
|
||||||
|
y C.int
|
||||||
|
z C.int
|
||||||
|
}
|
||||||
|
type C.struct_type1 struct {
|
||||||
|
_type C.int
|
||||||
|
__type C.int
|
||||||
|
___type C.int
|
||||||
|
}
|
||||||
|
type C.struct_type2 struct{ _type C.int }
|
||||||
|
|
||||||
func (s *C._Ctype_struct___9) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
|
func (union *C.union_1) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
|
||||||
func (s *C._Ctype_struct___9) set_bitfield_a(value C.uchar) {
|
func (union *C.union_1) unionfield_d() *float64 { return (*float64)(unsafe.Pointer(&union.$union)) }
|
||||||
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
|
func (union *C.union_1) unionfield_s() *C.short { return (*C.short)(unsafe.Pointer(&union.$union)) }
|
||||||
}
|
|
||||||
func (s *C._Ctype_struct___9) bitfield_b() C.uchar {
|
|
||||||
return s.__bitfield_1 >> 5 & 0x1
|
|
||||||
}
|
|
||||||
func (s *C._Ctype_struct___9) set_bitfield_b(value C.uchar) {
|
|
||||||
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
|
|
||||||
}
|
|
||||||
func (s *C._Ctype_struct___9) bitfield_c() C.uchar {
|
|
||||||
return s.__bitfield_1 >> 6
|
|
||||||
}
|
|
||||||
func (s *C._Ctype_struct___9) set_bitfield_c(value C.uchar,
|
|
||||||
|
|
||||||
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
|
type C.union_1 struct{ $union uint64 }
|
||||||
|
|
||||||
type C.bitfield_t = C._Ctype_struct___9
|
func (union *C.union_2) unionfield_area() *C.point2d_t {
|
||||||
|
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
func (union *C.union_2) unionfield_solid() *C.point3d_t {
|
||||||
|
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
|
||||||
|
type C.union_2 struct{ $union [3]uint32 }
|
||||||
|
|
||||||
|
func (union *C.union_3) unionfield_point() *C.point3d_t {
|
||||||
|
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
func (union *C.union_3) unionfield_array() *C.unionarray_t {
|
||||||
|
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
func (union *C.union_3) unionfield_thing() *C.union3_t {
|
||||||
|
return (*C.union3_t)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
|
||||||
|
type C.union_3 struct{ $union [2]uint64 }
|
||||||
|
|
||||||
|
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
|
||||||
|
func (union *C.union_union2d) unionfield_d() *[2]float64 {
|
||||||
|
return (*[2]float64)(unsafe.Pointer(&union.$union))
|
||||||
|
}
|
||||||
|
|
||||||
|
type C.union_union2d struct{ $union [2]uint64 }
|
||||||
|
type C.enum_option C.int
|
||||||
|
type C.enum_unused C.uint
|
||||||
|
|||||||
+11
-111
@@ -10,7 +10,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/shlex"
|
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,7 +72,9 @@ func (c *Config) BuildTags() []string {
|
|||||||
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))
|
||||||
}
|
}
|
||||||
tags = append(tags, c.Options.Tags...)
|
if extraTags := strings.Fields(c.Options.Tags); len(extraTags) != 0 {
|
||||||
|
tags = append(tags, extraTags...)
|
||||||
|
}
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,34 +176,6 @@ func (c *Config) AutomaticStackSize() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// StackSize returns the default stack size to be used for goroutines, if the
|
|
||||||
// stack size could not be determined automatically at compile time.
|
|
||||||
func (c *Config) StackSize() uint64 {
|
|
||||||
if c.Options.StackSize != 0 {
|
|
||||||
return c.Options.StackSize
|
|
||||||
}
|
|
||||||
return c.Target.DefaultStackSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// UseThinLTO returns whether ThinLTO should be used for the given target. Some
|
|
||||||
// targets (such as wasm) are not yet supported.
|
|
||||||
// We should try and remove as many exceptions as possible in the future, so
|
|
||||||
// that this optimization can be applied in more places.
|
|
||||||
func (c *Config) UseThinLTO() bool {
|
|
||||||
parts := strings.Split(c.Triple(), "-")
|
|
||||||
if parts[0] == "wasm32" {
|
|
||||||
// wasm-ld doesn't seem to support ThinLTO yet.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if parts[0] == "avr" || parts[0] == "xtensa" {
|
|
||||||
// These use external (GNU) linkers which might perhaps support ThinLTO
|
|
||||||
// through a plugin, but it's too much hassle to set up.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Other architectures support ThinLTO.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
||||||
@@ -244,29 +217,6 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
|
|||||||
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
|
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBinaryExtension returns the default extension for binaries, such as
|
|
||||||
// .exe, .wasm, or no extension (depending on the target).
|
|
||||||
func (c *Config) DefaultBinaryExtension() string {
|
|
||||||
parts := strings.Split(c.Triple(), "-")
|
|
||||||
if parts[0] == "wasm32" {
|
|
||||||
// WebAssembly files always have the .wasm file extension.
|
|
||||||
return ".wasm"
|
|
||||||
}
|
|
||||||
if len(parts) >= 3 && parts[2] == "windows" {
|
|
||||||
// Windows uses .exe.
|
|
||||||
return ".exe"
|
|
||||||
}
|
|
||||||
if len(parts) >= 3 && parts[2] == "unknown" {
|
|
||||||
// There appears to be a convention to use the .elf file extension for
|
|
||||||
// ELF files intended for microcontrollers. I'm not aware of the origin
|
|
||||||
// of this, it's just something that is used by many projects.
|
|
||||||
// I think it's a good tradition, so let's keep it.
|
|
||||||
return ".elf"
|
|
||||||
}
|
|
||||||
// Linux, MacOS, etc, don't use a file extension. Use it as a fallback.
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() []string {
|
||||||
@@ -275,18 +225,12 @@ func (c *Config) CFlags() []string {
|
|||||||
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
|
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
|
||||||
}
|
}
|
||||||
switch c.Target.Libc {
|
switch c.Target.Libc {
|
||||||
case "darwin-libSystem":
|
|
||||||
root := goenv.Get("TINYGOROOT")
|
|
||||||
cflags = append(cflags,
|
|
||||||
"--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
|
|
||||||
)
|
|
||||||
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,
|
"--sysroot="+path,
|
||||||
"-isystem", filepath.Join(path, "include"), // necessary for Xtensa
|
|
||||||
"-isystem", filepath.Join(picolibcDir, "include"),
|
"-isystem", filepath.Join(picolibcDir, "include"),
|
||||||
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
||||||
)
|
)
|
||||||
@@ -393,13 +337,6 @@ func (c *Config) BinaryFormat(ext string) string {
|
|||||||
return c.Target.BinaryFormat
|
return c.Target.BinaryFormat
|
||||||
}
|
}
|
||||||
return "bin"
|
return "bin"
|
||||||
case ".img":
|
|
||||||
// Image file. Only defined for the ESP32 at the moment, where it is a
|
|
||||||
// full (runnable) image that can be used in the Espressif QEMU fork.
|
|
||||||
if c.Target.BinaryFormat != "" {
|
|
||||||
return c.Target.BinaryFormat + "-img"
|
|
||||||
}
|
|
||||||
return "bin"
|
|
||||||
case ".hex":
|
case ".hex":
|
||||||
// Similar to bin, but includes the start address and is thus usually a
|
// Similar to bin, but includes the start address and is thus usually a
|
||||||
// better format.
|
// better format.
|
||||||
@@ -449,13 +386,13 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
|||||||
if openocdInterface == "" {
|
if openocdInterface == "" {
|
||||||
return nil, errors.New("OpenOCD programmer not set")
|
return nil, errors.New("OpenOCD programmer not set")
|
||||||
}
|
}
|
||||||
if !regexp.MustCompile(`^[\p{L}0-9_-]+$`).MatchString(openocdInterface) {
|
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(openocdInterface) {
|
||||||
return nil, fmt.Errorf("OpenOCD programmer has an invalid name: %#v", openocdInterface)
|
return nil, fmt.Errorf("OpenOCD programmer has an invalid name: %#v", openocdInterface)
|
||||||
}
|
}
|
||||||
if c.Target.OpenOCDTarget == "" {
|
if c.Target.OpenOCDTarget == "" {
|
||||||
return nil, errors.New("OpenOCD chip not set")
|
return nil, errors.New("OpenOCD chip not set")
|
||||||
}
|
}
|
||||||
if !regexp.MustCompile(`^[\p{L}0-9_-]+$`).MatchString(c.Target.OpenOCDTarget) {
|
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(c.Target.OpenOCDTarget) {
|
||||||
return nil, fmt.Errorf("OpenOCD target has an invalid name: %#v", c.Target.OpenOCDTarget)
|
return nil, fmt.Errorf("OpenOCD target has an invalid name: %#v", c.Target.OpenOCDTarget)
|
||||||
}
|
}
|
||||||
if c.Target.OpenOCDTransport != "" && c.Target.OpenOCDTransport != "swd" {
|
if c.Target.OpenOCDTransport != "" && c.Target.OpenOCDTransport != "swd" {
|
||||||
@@ -466,14 +403,7 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
|||||||
args = append(args, "-c", cmd)
|
args = append(args, "-c", cmd)
|
||||||
}
|
}
|
||||||
if c.Target.OpenOCDTransport != "" {
|
if c.Target.OpenOCDTransport != "" {
|
||||||
transport := c.Target.OpenOCDTransport
|
args = append(args, "-c", "transport select "+c.Target.OpenOCDTransport)
|
||||||
if transport == "swd" {
|
|
||||||
switch openocdInterface {
|
|
||||||
case "stlink-dap":
|
|
||||||
transport = "dapdirect_swd"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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")
|
||||||
return args, nil
|
return args, nil
|
||||||
@@ -507,43 +437,13 @@ func (c *Config) WasmAbi() string {
|
|||||||
return c.Target.WasmAbi
|
return c.Target.WasmAbi
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmulatorName is a shorthand to get the command for this emulator, something
|
// Emulator returns the emulator target config
|
||||||
// like qemu-system-arm or simavr.
|
func (c *Config) Emulator() []string {
|
||||||
func (c *Config) EmulatorName() string {
|
|
||||||
parts := strings.SplitN(c.Target.Emulator, " ", 2)
|
|
||||||
if len(parts) > 1 {
|
|
||||||
return parts[0]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmulatorFormat returns the binary format for the emulator and the associated
|
|
||||||
// file extension. An empty string means to pass directly whatever the linker
|
|
||||||
// produces directly without conversion (usually ELF format).
|
|
||||||
func (c *Config) EmulatorFormat() (format, fileExt string) {
|
|
||||||
switch {
|
|
||||||
case strings.Contains(c.Target.Emulator, "{img}"):
|
|
||||||
return "img", ".img"
|
|
||||||
default:
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emulator returns a ready-to-run command to run the given binary in an
|
|
||||||
// emulator. Give it the format (returned by EmulatorFormat()) and the path to
|
|
||||||
// the compiled binary.
|
|
||||||
func (c *Config) Emulator(format, binary string) ([]string, error) {
|
|
||||||
parts, err := shlex.Split(c.Target.Emulator)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse emulator command: %w", err)
|
|
||||||
}
|
|
||||||
var emulator []string
|
var emulator []string
|
||||||
for _, s := range parts {
|
for _, s := range c.Target.Emulator {
|
||||||
s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
|
emulator = append(emulator, strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT")))
|
||||||
s = strings.ReplaceAll(s, "{"+format+"}", binary)
|
|
||||||
emulator = append(emulator, s)
|
|
||||||
}
|
}
|
||||||
return emulator, nil
|
return emulator
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestConfig struct {
|
type TestConfig struct {
|
||||||
|
|||||||
+3
-10
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -28,20 +27,17 @@ type Options struct {
|
|||||||
GC string
|
GC string
|
||||||
PanicStrategy string
|
PanicStrategy string
|
||||||
Scheduler string
|
Scheduler string
|
||||||
StackSize uint64 // goroutine stack size (if none could be automatically determined)
|
|
||||||
Serial string
|
Serial string
|
||||||
Work bool // -work flag to print temporary build directory
|
|
||||||
InterpTimeout time.Duration
|
|
||||||
PrintIR bool
|
PrintIR bool
|
||||||
DumpSSA bool
|
DumpSSA bool
|
||||||
VerifyIR bool
|
VerifyIR bool
|
||||||
PrintCommands func(cmd string, args ...string) `json:"-"`
|
PrintCommands func(cmd string, args ...string)
|
||||||
Semaphore chan struct{} `json:"-"` // -p flag controls cap
|
Semaphore chan struct{} // -p flag controls cap
|
||||||
Debug bool
|
Debug bool
|
||||||
PrintSizes string
|
PrintSizes string
|
||||||
PrintAllocs *regexp.Regexp // regexp string
|
PrintAllocs *regexp.Regexp // regexp string
|
||||||
PrintStacks bool
|
PrintStacks bool
|
||||||
Tags []string
|
Tags string
|
||||||
WasmAbi string
|
WasmAbi string
|
||||||
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
||||||
TestConfig TestConfig
|
TestConfig TestConfig
|
||||||
@@ -49,9 +45,6 @@ type Options struct {
|
|||||||
OpenOCDCommands []string
|
OpenOCDCommands []string
|
||||||
LLVMFeatures string
|
LLVMFeatures string
|
||||||
Directory string
|
Directory string
|
||||||
PrintJSON bool
|
|
||||||
Monitor bool
|
|
||||||
BaudRate int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||||
|
|||||||
+43
-58
@@ -12,9 +12,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Target specification for a given target. Used for bare metal targets.
|
// Target specification for a given target. Used for bare metal targets.
|
||||||
@@ -42,8 +44,8 @@ type TargetSpec struct {
|
|||||||
LDFlags []string `json:"ldflags"`
|
LDFlags []string `json:"ldflags"`
|
||||||
LinkerScript string `json:"linkerscript"`
|
LinkerScript string `json:"linkerscript"`
|
||||||
ExtraFiles []string `json:"extra-files"`
|
ExtraFiles []string `json:"extra-files"`
|
||||||
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
||||||
Emulator string `json:"emulator"`
|
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
|
||||||
FlashCommand string `json:"flash-command"`
|
FlashCommand string `json:"flash-command"`
|
||||||
GDB []string `json:"gdb"`
|
GDB []string `json:"gdb"`
|
||||||
PortReset string `json:"flash-1200-bps-reset"`
|
PortReset string `json:"flash-1200-bps-reset"`
|
||||||
@@ -57,7 +59,6 @@ type TargetSpec struct {
|
|||||||
OpenOCDTarget string `json:"openocd-target"`
|
OpenOCDTarget string `json:"openocd-target"`
|
||||||
OpenOCDTransport string `json:"openocd-transport"`
|
OpenOCDTransport string `json:"openocd-transport"`
|
||||||
OpenOCDCommands []string `json:"openocd-commands"`
|
OpenOCDCommands []string `json:"openocd-commands"`
|
||||||
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
|
|
||||||
JLinkDevice string `json:"jlink-device"`
|
JLinkDevice string `json:"jlink-device"`
|
||||||
CodeModel string `json:"code-model"`
|
CodeModel string `json:"code-model"`
|
||||||
RelocationModel string `json:"relocation-model"`
|
RelocationModel string `json:"relocation-model"`
|
||||||
@@ -65,7 +66,7 @@ type TargetSpec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
||||||
func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
|
func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
|
||||||
specType := reflect.TypeOf(spec).Elem()
|
specType := reflect.TypeOf(spec).Elem()
|
||||||
specValue := reflect.ValueOf(spec).Elem()
|
specValue := reflect.ValueOf(spec).Elem()
|
||||||
childValue := reflect.ValueOf(child).Elem()
|
childValue := reflect.ValueOf(child).Elem()
|
||||||
@@ -88,22 +89,23 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
|
|||||||
if !src.IsNil() {
|
if !src.IsNil() {
|
||||||
dst.Set(src)
|
dst.Set(src)
|
||||||
}
|
}
|
||||||
case reflect.Slice: // for slices, append the field and check for duplicates
|
case reflect.Slice: // for slices...
|
||||||
dst.Set(reflect.AppendSlice(dst, src))
|
if src.Len() > 0 { // ... if not empty ...
|
||||||
for i := 0; i < dst.Len(); i++ {
|
switch tag := field.Tag.Get("override"); tag {
|
||||||
v := dst.Index(i).String()
|
case "copy":
|
||||||
for j := i + 1; j < dst.Len(); j++ {
|
// copy the field of child to spec
|
||||||
w := dst.Index(j).String()
|
dst.Set(src)
|
||||||
if v == w {
|
case "append", "":
|
||||||
return fmt.Errorf("duplicate value '%s' in field %s", v, field.Name)
|
// or append the field of child to spec
|
||||||
}
|
dst.Set(reflect.AppendSlice(dst, src))
|
||||||
|
default:
|
||||||
|
panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown field type: %s", kind)
|
panic("unknown field type : " + kind.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// load reads a target specification from the JSON in the given io.Reader. It
|
// load reads a target specification from the JSON in the given io.Reader. It
|
||||||
@@ -118,10 +120,10 @@ func (spec *TargetSpec) load(r io.Reader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loadFromGivenStr loads the TargetSpec from the given string that could be:
|
// loadFromGivenStr loads the TargetSpec from the given string that could be:
|
||||||
// - targets/ directory inside the compiler sources
|
// - targets/ directory inside the compiler sources
|
||||||
// - a relative or absolute path to custom (project specific) target specification .json file;
|
// - a relative or absolute path to custom (project specific) target specification .json file;
|
||||||
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
|
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
|
||||||
// as well as path to custom files (ex. myAwesomeProject.json)
|
// as well as path to custom files (ex. myAwesomeProject.json)
|
||||||
func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
||||||
path := ""
|
path := ""
|
||||||
if strings.HasSuffix(str, ".json") {
|
if strings.HasSuffix(str, ".json") {
|
||||||
@@ -151,17 +153,11 @@ func (spec *TargetSpec) resolveInherits() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = newSpec.overrideProperties(subtarget)
|
newSpec.overrideProperties(subtarget)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When all properties are loaded, make sure they are properly inherited.
|
// When all properties are loaded, make sure they are properly inherited.
|
||||||
err := newSpec.overrideProperties(spec)
|
newSpec.overrideProperties(spec)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*spec = *newSpec
|
*spec = *newSpec
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -209,10 +205,11 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
// triples for historical reasons) have the form:
|
// triples for historical reasons) have the form:
|
||||||
// arch-vendor-os-environment
|
// arch-vendor-os-environment
|
||||||
target := llvmarch + "-unknown-" + llvmos
|
target := llvmarch + "-unknown-" + llvmos
|
||||||
|
if options.GOARCH == "arm" {
|
||||||
|
target += "-gnueabihf"
|
||||||
|
}
|
||||||
if options.GOOS == "windows" {
|
if options.GOOS == "windows" {
|
||||||
target += "-gnu"
|
target += "-gnu"
|
||||||
} else if options.GOARCH == "arm" {
|
|
||||||
target += "-gnueabihf"
|
|
||||||
}
|
}
|
||||||
return defaultTarget(options.GOOS, options.GOARCH, target)
|
return defaultTarget(options.GOOS, options.GOARCH, target)
|
||||||
}
|
}
|
||||||
@@ -228,7 +225,7 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
// it includes all parents as specified in the "inherits" key.
|
// it includes all parents as specified in the "inherits" key.
|
||||||
err = spec.resolveInherits()
|
err = spec.resolveInherits()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s : %w", options.Target, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.Scheduler == "asyncify" {
|
if spec.Scheduler == "asyncify" {
|
||||||
@@ -261,7 +258,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
spec.Features = "+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")
|
||||||
switch strings.Split(triple, "-")[0] {
|
switch strings.Split(triple, "-")[0] {
|
||||||
case "armv5":
|
case "armv5":
|
||||||
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||||
@@ -275,16 +272,8 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.Features = "+neon"
|
spec.Features = "+neon"
|
||||||
}
|
}
|
||||||
if goos == "darwin" {
|
if goos == "darwin" {
|
||||||
spec.Linker = "ld.lld"
|
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
|
||||||
spec.Libc = "darwin-libSystem"
|
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
||||||
arch := strings.Split(triple, "-")[0]
|
|
||||||
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
|
|
||||||
spec.LDFlags = append(spec.LDFlags,
|
|
||||||
"-flavor", "darwin",
|
|
||||||
"-dead_strip",
|
|
||||||
"-arch", arch,
|
|
||||||
"-platform_version", "macos", platformVersion, platformVersion,
|
|
||||||
)
|
|
||||||
} else if goos == "linux" {
|
} else if goos == "linux" {
|
||||||
spec.Linker = "ld.lld"
|
spec.Linker = "ld.lld"
|
||||||
spec.RTLib = "compiler-rt"
|
spec.RTLib = "compiler-rt"
|
||||||
@@ -305,8 +294,13 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
"--image-base", "0x400000",
|
"--image-base", "0x400000",
|
||||||
"--gc-sections",
|
"--gc-sections",
|
||||||
"--no-insert-timestamp",
|
"--no-insert-timestamp",
|
||||||
"--no-dynamicbase",
|
|
||||||
)
|
)
|
||||||
|
llvmMajor, _ := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
|
||||||
|
if llvmMajor >= 12 {
|
||||||
|
// This flag was added in LLVM 12. At the same time, LLVM 12
|
||||||
|
// switched the default from --dynamicbase to --no-dynamicbase.
|
||||||
|
spec.LDFlags = append(spec.LDFlags, "--no-dynamicbase")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||||
}
|
}
|
||||||
@@ -317,31 +311,22 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
// systems so we need separate assembly files.
|
// systems so we need separate assembly files.
|
||||||
suffix = "_windows"
|
suffix = "_windows"
|
||||||
}
|
}
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+goarch+suffix+".S")
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_"+goarch+suffix+".S")
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+goarch+suffix+".S")
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+goarch+suffix+".S")
|
||||||
}
|
}
|
||||||
if goarch != runtime.GOARCH {
|
if goarch != runtime.GOARCH {
|
||||||
// Some educated guesses as to how to invoke helper programs.
|
// Some educated guesses as to how to invoke helper programs.
|
||||||
spec.GDB = []string{"gdb-multiarch"}
|
spec.GDB = []string{"gdb-multiarch"}
|
||||||
if goos == "linux" {
|
if goarch == "arm" && goos == "linux" {
|
||||||
switch goarch {
|
spec.Emulator = []string{"qemu-arm"}
|
||||||
case "386":
|
}
|
||||||
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
|
if goarch == "arm64" && goos == "linux" {
|
||||||
if runtime.GOARCH != "amd64" {
|
spec.Emulator = []string{"qemu-aarch64"}
|
||||||
spec.Emulator = "qemu-i386 {}"
|
|
||||||
}
|
|
||||||
case "amd64":
|
|
||||||
spec.Emulator = "qemu-x86_64 {}"
|
|
||||||
case "arm":
|
|
||||||
spec.Emulator = "qemu-arm {}"
|
|
||||||
case "arm64":
|
|
||||||
spec.Emulator = "qemu-aarch64 {}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if goos != runtime.GOOS {
|
if goos != runtime.GOOS {
|
||||||
if goos == "windows" {
|
if goos == "windows" {
|
||||||
spec.Emulator = "wine {}"
|
spec.Emulator = []string{"wine"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &spec, nil
|
return &spec, nil
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package compileopts
|
package compileopts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"os"
|
||||||
"io/fs"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -18,7 +17,7 @@ func TestLoadTarget(t *testing.T) {
|
|||||||
t.Error("LoadTarget should have failed with non existing target")
|
t.Error("LoadTarget should have failed with non existing target")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !os.IsNotExist(err) {
|
||||||
t.Error("LoadTarget failed for wrong reason:", err)
|
t.Error("LoadTarget failed for wrong reason:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +29,7 @@ func TestOverrideProperties(t *testing.T) {
|
|||||||
CPU: "baseCpu",
|
CPU: "baseCpu",
|
||||||
CFlags: []string{"-base-foo", "-base-bar"},
|
CFlags: []string{"-base-foo", "-base-bar"},
|
||||||
BuildTags: []string{"bt1", "bt2"},
|
BuildTags: []string{"bt1", "bt2"},
|
||||||
|
Emulator: []string{"be1", "be2"},
|
||||||
DefaultStackSize: 42,
|
DefaultStackSize: 42,
|
||||||
AutoStackSize: &baseAutoStackSize,
|
AutoStackSize: &baseAutoStackSize,
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,7 @@ func TestOverrideProperties(t *testing.T) {
|
|||||||
GOOS: "",
|
GOOS: "",
|
||||||
CPU: "chlidCpu",
|
CPU: "chlidCpu",
|
||||||
CFlags: []string{"-child-foo", "-child-bar"},
|
CFlags: []string{"-child-foo", "-child-bar"},
|
||||||
|
Emulator: []string{"ce1", "ce2"},
|
||||||
AutoStackSize: &childAutoStackSize,
|
AutoStackSize: &childAutoStackSize,
|
||||||
DefaultStackSize: 64,
|
DefaultStackSize: 64,
|
||||||
}
|
}
|
||||||
@@ -56,6 +57,9 @@ func TestOverrideProperties(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
|
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
|
||||||
t.Errorf("Overriding failed : got %v", base.BuildTags)
|
t.Errorf("Overriding failed : got %v", base.BuildTags)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
|
||||||
|
t.Errorf("Overriding failed : got %v", base.Emulator)
|
||||||
|
}
|
||||||
if *base.AutoStackSize != false {
|
if *base.AutoStackSize != false {
|
||||||
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
|
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-3
@@ -16,8 +16,6 @@ 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.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",
|
||||||
@@ -25,10 +23,53 @@ var stdlibAliases = map[string]string{
|
|||||||
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
||||||
|
|
||||||
// math package
|
// math package
|
||||||
|
"math.Asin": "math.asin",
|
||||||
|
"math.Asinh": "math.asinh",
|
||||||
|
"math.Acos": "math.acos",
|
||||||
|
"math.Acosh": "math.acosh",
|
||||||
|
"math.Atan": "math.atan",
|
||||||
|
"math.Atanh": "math.atanh",
|
||||||
|
"math.Atan2": "math.atan2",
|
||||||
|
"math.Cbrt": "math.cbrt",
|
||||||
|
"math.Ceil": "math.ceil",
|
||||||
|
"math.archCeil": "math.ceil",
|
||||||
|
"math.Cos": "math.cos",
|
||||||
|
"math.Cosh": "math.cosh",
|
||||||
|
"math.Erf": "math.erf",
|
||||||
|
"math.Erfc": "math.erfc",
|
||||||
|
"math.Exp": "math.exp",
|
||||||
|
"math.archExp": "math.exp",
|
||||||
|
"math.Expm1": "math.expm1",
|
||||||
|
"math.Exp2": "math.exp2",
|
||||||
|
"math.archExp2": "math.exp2",
|
||||||
|
"math.Floor": "math.floor",
|
||||||
|
"math.archFloor": "math.floor",
|
||||||
|
"math.Frexp": "math.frexp",
|
||||||
|
"math.Hypot": "math.hypot",
|
||||||
"math.archHypot": "math.hypot",
|
"math.archHypot": "math.hypot",
|
||||||
|
"math.Ldexp": "math.ldexp",
|
||||||
|
"math.Log": "math.log",
|
||||||
|
"math.archLog": "math.log",
|
||||||
|
"math.Log1p": "math.log1p",
|
||||||
|
"math.Log10": "math.log10",
|
||||||
|
"math.Log2": "math.log2",
|
||||||
|
"math.Max": "math.max",
|
||||||
"math.archMax": "math.max",
|
"math.archMax": "math.max",
|
||||||
|
"math.Min": "math.min",
|
||||||
"math.archMin": "math.min",
|
"math.archMin": "math.min",
|
||||||
|
"math.Mod": "math.mod",
|
||||||
|
"math.Modf": "math.modf",
|
||||||
"math.archModf": "math.modf",
|
"math.archModf": "math.modf",
|
||||||
|
"math.Pow": "math.pow",
|
||||||
|
"math.Remainder": "math.remainder",
|
||||||
|
"math.Sin": "math.sin",
|
||||||
|
"math.Sinh": "math.sinh",
|
||||||
|
"math.Sqrt": "math.sqrt",
|
||||||
|
"math.archSqrt": "math.sqrt",
|
||||||
|
"math.Tan": "math.tan",
|
||||||
|
"math.Tanh": "math.tanh",
|
||||||
|
"math.Trunc": "math.trunc",
|
||||||
|
"math.archTrunc": "math.trunc",
|
||||||
}
|
}
|
||||||
|
|
||||||
// createAlias implements the function (in the builder) as a call to the alias
|
// createAlias implements the function (in the builder) as a call to the alias
|
||||||
@@ -45,7 +86,7 @@ func (b *builder) createAlias(alias llvm.Value) {
|
|||||||
pos := b.program.Fset.Position(b.fn.Pos())
|
pos := b.program.Fset.Position(b.fn.Pos())
|
||||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
entryBlock := b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
entryBlock := llvm.AddBasicBlock(b.llvmFn, "entry")
|
||||||
b.SetInsertPointAtEnd(entryBlock)
|
b.SetInsertPointAtEnd(entryBlock)
|
||||||
if b.llvmFn.Type() != alias.Type() {
|
if b.llvmFn.Type() != alias.Type() {
|
||||||
b.addError(b.fn.Pos(), "alias function should have the same type as aliasee "+alias.Name())
|
b.addError(b.fn.Pos(), "alias function should have the same type as aliasee "+alias.Name())
|
||||||
|
|||||||
+1
-3
@@ -240,10 +240,8 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the fault block at the end of the function and the next block at the
|
|
||||||
// current insert position.
|
|
||||||
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||||
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
|
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".next")
|
||||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||||
|
|
||||||
// Now branch to the out-of-bounds or the regular block.
|
// Now branch to the out-of-bounds or the regular block.
|
||||||
|
|||||||
+48
-25
@@ -4,17 +4,19 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// createAtomicOp lowers a sync/atomic function by lowering it as an LLVM atomic
|
// createAtomicOp lowers an atomic library call by lowering it as an LLVM atomic
|
||||||
// operation. It returns the result of the operation, or a zero llvm.Value if
|
// operation. It returns the result of the operation and true if the call could
|
||||||
// the result is void.
|
// be lowered inline, and false otherwise.
|
||||||
func (b *builder) createAtomicOp(name string) llvm.Value {
|
func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
|
||||||
|
name := call.Value.(*ssa.Function).Name()
|
||||||
switch name {
|
switch name {
|
||||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||||
ptr := b.getValue(b.fn.Params[0])
|
ptr := b.getValue(call.Args[0])
|
||||||
val := b.getValue(b.fn.Params[1])
|
val := b.getValue(call.Args[1])
|
||||||
if strings.HasPrefix(b.Triple, "avr") {
|
if strings.HasPrefix(b.Triple, "avr") {
|
||||||
// AtomicRMW does not work on AVR as intended:
|
// 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)
|
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
|
||||||
@@ -27,18 +29,17 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
|||||||
}
|
}
|
||||||
oldVal := b.createCall(fn, []llvm.Value{ptr, val}, "")
|
oldVal := b.createCall(fn, []llvm.Value{ptr, val}, "")
|
||||||
// Return the new value, not the original value returned.
|
// Return the new value, not the original value returned.
|
||||||
return b.CreateAdd(oldVal, val, "")
|
return b.CreateAdd(oldVal, val, ""), true
|
||||||
}
|
}
|
||||||
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, ""), true
|
||||||
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
||||||
ptr := b.getValue(b.fn.Params[0])
|
ptr := b.getValue(call.Args[0])
|
||||||
val := b.getValue(b.fn.Params[1])
|
val := b.getValue(call.Args[1])
|
||||||
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
|
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
|
||||||
if isPointer {
|
if isPointer {
|
||||||
// atomicrmw only supports integers, so cast to an integer.
|
// atomicrmw only supports integers, so cast to an integer.
|
||||||
// TODO: this is fixed in LLVM 15.
|
|
||||||
val = b.CreatePtrToInt(val, b.uintptrType, "")
|
val = b.CreatePtrToInt(val, b.uintptrType, "")
|
||||||
ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "")
|
ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "")
|
||||||
}
|
}
|
||||||
@@ -46,23 +47,47 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
|||||||
if isPointer {
|
if isPointer {
|
||||||
oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "")
|
oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "")
|
||||||
}
|
}
|
||||||
return oldVal
|
return oldVal, true
|
||||||
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
||||||
ptr := b.getValue(b.fn.Params[0])
|
ptr := b.getValue(call.Args[0])
|
||||||
old := b.getValue(b.fn.Params[1])
|
old := b.getValue(call.Args[1])
|
||||||
newVal := b.getValue(b.fn.Params[2])
|
newVal := b.getValue(call.Args[2])
|
||||||
|
if strings.HasSuffix(name, "64") {
|
||||||
|
if strings.HasPrefix(b.Triple, "thumb") {
|
||||||
|
// Work around a bug in LLVM, at least LLVM 11:
|
||||||
|
// https://reviews.llvm.org/D95891
|
||||||
|
// Check for thumbv6m, thumbv7, thumbv7em, and perhaps others.
|
||||||
|
// See also: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
|
||||||
|
compareAndSwap := b.mod.NamedFunction("__sync_val_compare_and_swap_8")
|
||||||
|
if compareAndSwap.IsNil() {
|
||||||
|
// Declare the function if it isn't already declared.
|
||||||
|
i64Type := b.ctx.Int64Type()
|
||||||
|
fnType := llvm.FunctionType(i64Type, []llvm.Type{llvm.PointerType(i64Type, 0), i64Type, i64Type}, false)
|
||||||
|
compareAndSwap = llvm.AddFunction(b.mod, "__sync_val_compare_and_swap_8", fnType)
|
||||||
|
}
|
||||||
|
actualOldValue := b.CreateCall(compareAndSwap, []llvm.Value{ptr, old, newVal}, "")
|
||||||
|
// The __sync_val_compare_and_swap_8 function returns the old
|
||||||
|
// value. However, we shouldn't return the old value, we should
|
||||||
|
// return whether the compare/exchange was successful. This is
|
||||||
|
// easily done by comparing the returned (actual) old value with
|
||||||
|
// the expected old value passed to
|
||||||
|
// __sync_val_compare_and_swap_8.
|
||||||
|
swapped := b.CreateICmp(llvm.IntEQ, old, actualOldValue, "")
|
||||||
|
return swapped, true
|
||||||
|
}
|
||||||
|
}
|
||||||
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
|
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||||
swapped := b.CreateExtractValue(tuple, 1, "")
|
swapped := b.CreateExtractValue(tuple, 1, "")
|
||||||
return swapped
|
return swapped, true
|
||||||
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
|
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
|
||||||
ptr := b.getValue(b.fn.Params[0])
|
ptr := b.getValue(call.Args[0])
|
||||||
val := b.CreateLoad(ptr, "")
|
val := b.CreateLoad(ptr, "")
|
||||||
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||||
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||||
return val
|
return val, true
|
||||||
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
||||||
ptr := b.getValue(b.fn.Params[0])
|
ptr := b.getValue(call.Args[0])
|
||||||
val := b.getValue(b.fn.Params[1])
|
val := b.getValue(call.Args[1])
|
||||||
if strings.HasPrefix(b.Triple, "avr") {
|
if strings.HasPrefix(b.Triple, "avr") {
|
||||||
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
|
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
|
||||||
vType := val.Type()
|
vType := val.Type()
|
||||||
@@ -78,15 +103,13 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
|||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
|
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
|
||||||
}
|
}
|
||||||
b.createCall(fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, "")
|
return b.createCall(fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, ""), true
|
||||||
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
|
||||||
return llvm.Value{}
|
return store, true
|
||||||
default:
|
default:
|
||||||
b.addError(b.fn.Pos(), "unknown atomic operation: "+b.fn.Name())
|
return llvm.Value{}, false
|
||||||
return llvm.Value{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-30
@@ -33,36 +33,17 @@ const (
|
|||||||
paramIsDeferenceableOrNull = 1 << iota
|
paramIsDeferenceableOrNull = 1 << iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
// createCall creates a new call to runtime.<fnName> with the given arguments.
|
||||||
// createRuntimeInvoke instead.
|
func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name string) llvm.Value {
|
||||||
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
|
|
||||||
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
|
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
|
||||||
llvmFn := b.getFunction(fn)
|
llvmFn := b.getFunction(fn)
|
||||||
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.i8ptrType)) // unused context parameter
|
||||||
if isInvoke {
|
|
||||||
return b.createInvoke(llvmFn, args, name)
|
|
||||||
}
|
|
||||||
return b.createCall(llvmFn, args, name)
|
return b.createCall(llvmFn, args, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRuntimeCall creates a new call to runtime.<fnName> with the given
|
|
||||||
// arguments.
|
|
||||||
func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name string) llvm.Value {
|
|
||||||
return b.createRuntimeCallCommon(fnName, args, name, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createRuntimeInvoke creates a new call to runtime.<fnName> with the given
|
|
||||||
// arguments. If the runtime call panics, control flow is diverted to the
|
|
||||||
// landing pad block.
|
|
||||||
// Note that "invoke" here is meant in the LLVM sense (a call that can
|
|
||||||
// panic/throw), not in the Go sense (an interface method call).
|
|
||||||
func (b *builder) createRuntimeInvoke(fnName string, args []llvm.Value, name string) llvm.Value {
|
|
||||||
return b.createRuntimeCallCommon(fnName, args, name, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createCall creates a call to the given function with the arguments possibly
|
// createCall creates a call to the given function with the arguments possibly
|
||||||
// expanded.
|
// expanded.
|
||||||
func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm.Value {
|
func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm.Value {
|
||||||
@@ -74,15 +55,6 @@ func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm
|
|||||||
return b.CreateCall(fn, expanded, name)
|
return b.CreateCall(fn, expanded, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createInvoke is like createCall but continues execution at the landing pad if
|
|
||||||
// the call resulted in a panic.
|
|
||||||
func (b *builder) createInvoke(fn llvm.Value, args []llvm.Value, name string) llvm.Value {
|
|
||||||
if b.hasDeferFrame() {
|
|
||||||
b.createInvokeCheckpoint()
|
|
||||||
}
|
|
||||||
return b.createCall(fn, args, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand an argument type to a list that can be used in a function call
|
// Expand an argument type to a list that can be used in a function call
|
||||||
// parameter list.
|
// parameter list.
|
||||||
func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||||
|
|||||||
+87
-328
@@ -9,7 +9,6 @@ import (
|
|||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -18,7 +17,6 @@ import (
|
|||||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||||
"github.com/tinygo-org/tinygo/loader"
|
"github.com/tinygo-org/tinygo/loader"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
"golang.org/x/tools/go/types/typeutil"
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@ type compilerContext struct {
|
|||||||
cu llvm.Metadata
|
cu llvm.Metadata
|
||||||
difiles map[string]llvm.Metadata
|
difiles map[string]llvm.Metadata
|
||||||
ditypes map[types.Type]llvm.Metadata
|
ditypes map[types.Type]llvm.Metadata
|
||||||
llvmTypes typeutil.Map
|
llvmTypes map[types.Type]llvm.Type
|
||||||
machine llvm.TargetMachine
|
machine llvm.TargetMachine
|
||||||
targetData llvm.TargetData
|
targetData llvm.TargetData
|
||||||
intType llvm.Type
|
intType llvm.Type
|
||||||
@@ -78,7 +76,6 @@ type compilerContext struct {
|
|||||||
program *ssa.Program
|
program *ssa.Program
|
||||||
diagnostics []error
|
diagnostics []error
|
||||||
astComments map[string]*ast.CommentGroup
|
astComments map[string]*ast.CommentGroup
|
||||||
embedGlobals map[string][]*loader.EmbedFile
|
|
||||||
pkg *types.Package
|
pkg *types.Package
|
||||||
packageDir string // directory for this package
|
packageDir string // directory for this package
|
||||||
runtimePkg *types.Package
|
runtimePkg *types.Package
|
||||||
@@ -92,6 +89,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
|
|||||||
DumpSSA: dumpSSA,
|
DumpSSA: dumpSSA,
|
||||||
difiles: make(map[string]llvm.Metadata),
|
difiles: make(map[string]llvm.Metadata),
|
||||||
ditypes: make(map[types.Type]llvm.Metadata),
|
ditypes: make(map[types.Type]llvm.Metadata),
|
||||||
|
llvmTypes: make(map[types.Type]llvm.Type),
|
||||||
machine: machine,
|
machine: machine,
|
||||||
targetData: machine.CreateTargetData(),
|
targetData: machine.CreateTargetData(),
|
||||||
astComments: map[string]*ast.CommentGroup{},
|
astComments: map[string]*ast.CommentGroup{},
|
||||||
@@ -139,8 +137,6 @@ type builder struct {
|
|||||||
currentBlock *ssa.BasicBlock
|
currentBlock *ssa.BasicBlock
|
||||||
phis []phiNode
|
phis []phiNode
|
||||||
deferPtr llvm.Value
|
deferPtr llvm.Value
|
||||||
deferFrame llvm.Value
|
|
||||||
landingpad llvm.BasicBlock
|
|
||||||
difunc llvm.Metadata
|
difunc llvm.Metadata
|
||||||
dilocals map[*types.Var]llvm.Metadata
|
dilocals map[*types.Var]llvm.Metadata
|
||||||
initInlinedAt llvm.Metadata // fake inlinedAt position
|
initInlinedAt llvm.Metadata // fake inlinedAt position
|
||||||
@@ -238,15 +234,10 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
|
|||||||
panic("unknown pointer size")
|
panic("unknown pointer size")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a complex128 type because that's likely the type with the
|
|
||||||
// biggest alignment on most/all ABIs.
|
|
||||||
ctx := llvm.NewContext()
|
|
||||||
defer ctx.Dispose()
|
|
||||||
complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false)
|
|
||||||
return &stdSizes{
|
return &stdSizes{
|
||||||
IntSize: int64(intWidth / 8),
|
IntSize: int64(intWidth / 8),
|
||||||
PtrSize: int64(targetData.PointerSize()),
|
PtrSize: int64(targetData.PointerSize()),
|
||||||
MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)),
|
MaxAlign: int64(targetData.PrefTypeAlignment(targetData.IntPtrType())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +245,6 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
|
|||||||
func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
|
func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
|
||||||
c := newCompilerContext(moduleName, machine, config, dumpSSA)
|
c := newCompilerContext(moduleName, machine, config, dumpSSA)
|
||||||
c.packageDir = pkg.OriginalDir()
|
c.packageDir = pkg.OriginalDir()
|
||||||
c.embedGlobals = pkg.EmbedGlobals
|
|
||||||
c.pkg = pkg.Pkg
|
c.pkg = pkg.Pkg
|
||||||
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
|
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
|
||||||
c.program = ssaPkg.Prog
|
c.program = ssaPkg.Prog
|
||||||
@@ -306,7 +296,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
c.dibuilder.Finalize()
|
c.dibuilder.Finalize()
|
||||||
c.dibuilder.Destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.mod, c.diagnostics
|
return c.mod, c.diagnostics
|
||||||
@@ -325,16 +314,12 @@ func (c *compilerContext) getLLVMRuntimeType(name string) llvm.Type {
|
|||||||
// important for named struct types (which should only be created once).
|
// important for named struct types (which should only be created once).
|
||||||
func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
|
func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
|
||||||
// Try to load the LLVM type from the cache.
|
// Try to load the LLVM type from the cache.
|
||||||
// Note: *types.Named isn't unique when working with generics.
|
if t, ok := c.llvmTypes[goType]; ok {
|
||||||
// See https://github.com/golang/go/issues/53914
|
return t
|
||||||
// This is the reason for using typeutil.Map to lookup LLVM types for Go types.
|
|
||||||
ival := c.llvmTypes.At(goType)
|
|
||||||
if ival != nil {
|
|
||||||
return ival.(llvm.Type)
|
|
||||||
}
|
}
|
||||||
// Not already created, so adding this type to the cache.
|
// Not already created, so adding this type to the cache.
|
||||||
llvmType := c.makeLLVMType(goType)
|
llvmType := c.makeLLVMType(goType)
|
||||||
c.llvmTypes.Set(goType, llvmType)
|
c.llvmTypes[goType] = llvmType
|
||||||
return llvmType
|
return llvmType
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,9 +373,9 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
|||||||
// in LLVM IR, named structs are implemented as named structs in
|
// in LLVM IR, named structs are implemented as named structs in
|
||||||
// LLVM. This is because it is otherwise impossible to create
|
// LLVM. This is because it is otherwise impossible to create
|
||||||
// self-referencing types such as linked lists.
|
// self-referencing types such as linked lists.
|
||||||
llvmName := typ.String()
|
llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name()
|
||||||
llvmType := c.ctx.StructCreateNamed(llvmName)
|
llvmType := c.ctx.StructCreateNamed(llvmName)
|
||||||
c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion
|
c.llvmTypes[goType] = llvmType // avoid infinite recursion
|
||||||
underlying := c.getLLVMType(st)
|
underlying := c.getLLVMType(st)
|
||||||
llvmType.StructSetBody(underlying.StructElementTypes(), false)
|
llvmType.StructSetBody(underlying.StructElementTypes(), false)
|
||||||
return llvmType
|
return llvmType
|
||||||
@@ -415,8 +400,6 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
|||||||
members[i] = c.getLLVMType(typ.Field(i).Type())
|
members[i] = c.getLLVMType(typ.Field(i).Type())
|
||||||
}
|
}
|
||||||
return c.ctx.StructType(members, false)
|
return c.ctx.StructType(members, false)
|
||||||
case *types.TypeParam:
|
|
||||||
return c.getLLVMType(typ.Underlying())
|
|
||||||
case *types.Tuple:
|
case *types.Tuple:
|
||||||
members := make([]llvm.Type, typ.Len())
|
members := make([]llvm.Type, typ.Len())
|
||||||
for i := 0; i < typ.Len(); i++ {
|
for i := 0; i < typ.Len(); i++ {
|
||||||
@@ -615,8 +598,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
|||||||
})
|
})
|
||||||
temporaryMDNode.ReplaceAllUsesWith(md)
|
temporaryMDNode.ReplaceAllUsesWith(md)
|
||||||
return md
|
return md
|
||||||
case *types.TypeParam:
|
|
||||||
return c.getDIType(typ.Underlying())
|
|
||||||
default:
|
default:
|
||||||
panic("unknown type while generating DWARF debug type: " + typ.String())
|
panic("unknown type while generating DWARF debug type: " + typ.String())
|
||||||
}
|
}
|
||||||
@@ -686,7 +667,7 @@ func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
|
|||||||
Name: param.Name(),
|
Name: param.Name(),
|
||||||
File: b.getDIFile(pos.Filename),
|
File: b.getDIFile(pos.Filename),
|
||||||
Line: pos.Line,
|
Line: pos.Line,
|
||||||
Type: b.getDIType(param.Type()),
|
Type: b.getDIType(variable.Type()),
|
||||||
AlwaysPreserve: true,
|
AlwaysPreserve: true,
|
||||||
ArgNo: i + 1,
|
ArgNo: i + 1,
|
||||||
})
|
})
|
||||||
@@ -784,25 +765,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
member := pkg.Members[name]
|
member := pkg.Members[name]
|
||||||
switch member := member.(type) {
|
switch member := member.(type) {
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
if member.Synthetic == "generic function" {
|
|
||||||
// Do not try to build generic (non-instantiated) functions.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Create the function definition.
|
// Create the function definition.
|
||||||
b := newBuilder(c, irbuilder, member)
|
b := newBuilder(c, irbuilder, member)
|
||||||
if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok {
|
|
||||||
// The body of this function (if there is one) is ignored and
|
|
||||||
// replaced with a LLVM intrinsic call.
|
|
||||||
b.defineMathOp()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if member.Blocks == nil {
|
if member.Blocks == nil {
|
||||||
// Try to define this as an intrinsic function.
|
continue // external function
|
||||||
b.defineIntrinsicFunction()
|
|
||||||
// It might not be an intrinsic function but simply an external
|
|
||||||
// function (defined via //go:linkname). Leave it undefined in
|
|
||||||
// that case.
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
b.createFunction()
|
b.createFunction()
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
@@ -819,9 +785,6 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
for _, method := range methods {
|
for _, method := range methods {
|
||||||
// Parse this method.
|
// Parse this method.
|
||||||
fn := pkg.Prog.MethodValue(method)
|
fn := pkg.Prog.MethodValue(method)
|
||||||
if fn == nil {
|
|
||||||
continue // probably a generic method
|
|
||||||
}
|
|
||||||
if fn.Blocks == nil {
|
if fn.Blocks == nil {
|
||||||
continue // external function
|
continue // external function
|
||||||
}
|
}
|
||||||
@@ -846,9 +809,7 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
// Global variable.
|
// Global variable.
|
||||||
info := c.getGlobalInfo(member)
|
info := c.getGlobalInfo(member)
|
||||||
global := c.getGlobal(member)
|
global := c.getGlobal(member)
|
||||||
if files, ok := c.embedGlobals[member.Name()]; ok {
|
if !info.extern {
|
||||||
c.createEmbedGlobal(member, global, files)
|
|
||||||
} else if !info.extern {
|
|
||||||
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
if info.section != "" {
|
if info.section != "" {
|
||||||
@@ -882,155 +843,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// createEmbedGlobal creates an initializer for a //go:embed global variable.
|
// createFunction builds the LLVM IR implementation for this function. The
|
||||||
func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Value, files []*loader.EmbedFile) {
|
// function must not yet be defined, otherwise this function will create a
|
||||||
switch typ := member.Type().(*types.Pointer).Elem().Underlying().(type) {
|
// diagnostic.
|
||||||
case *types.Basic:
|
func (b *builder) createFunction() {
|
||||||
// String type.
|
|
||||||
if typ.Kind() != types.String {
|
|
||||||
// This is checked at the AST level, so should be unreachable.
|
|
||||||
panic("expected a string type")
|
|
||||||
}
|
|
||||||
if len(files) != 1 {
|
|
||||||
c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
strObj := c.getEmbedFileString(files[0])
|
|
||||||
global.SetInitializer(strObj)
|
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
|
||||||
|
|
||||||
case *types.Slice:
|
|
||||||
if typ.Elem().Underlying().(*types.Basic).Kind() != types.Byte {
|
|
||||||
// This is checked at the AST level, so should be unreachable.
|
|
||||||
panic("expected a byte slice")
|
|
||||||
}
|
|
||||||
if len(files) != 1 {
|
|
||||||
c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := files[0]
|
|
||||||
bufferValue := c.ctx.ConstString(string(file.Data), false)
|
|
||||||
bufferGlobal := llvm.AddGlobal(c.mod, bufferValue.Type(), c.pkg.Path()+"$embedslice")
|
|
||||||
bufferGlobal.SetInitializer(bufferValue)
|
|
||||||
bufferGlobal.SetLinkage(llvm.InternalLinkage)
|
|
||||||
bufferGlobal.SetAlignment(1)
|
|
||||||
slicePtr := llvm.ConstInBoundsGEP(bufferGlobal, []llvm.Value{
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
})
|
|
||||||
sliceLen := llvm.ConstInt(c.uintptrType, file.Size, false)
|
|
||||||
sliceObj := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false)
|
|
||||||
global.SetInitializer(sliceObj)
|
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
|
||||||
|
|
||||||
case *types.Struct:
|
|
||||||
// Assume this is an embed.FS struct:
|
|
||||||
// https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/embed/embed.go;l=148
|
|
||||||
// It looks like this:
|
|
||||||
// type FS struct {
|
|
||||||
// files *file
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Make a slice of the files, as they will appear in the binary. They
|
|
||||||
// are sorted in a special way to allow for binary searches, see
|
|
||||||
// src/embed/embed.go for details.
|
|
||||||
dirset := map[string]struct{}{}
|
|
||||||
var allFiles []*loader.EmbedFile
|
|
||||||
for _, file := range files {
|
|
||||||
allFiles = append(allFiles, file)
|
|
||||||
dirname := file.Name
|
|
||||||
for {
|
|
||||||
dirname, _ = path.Split(path.Clean(dirname))
|
|
||||||
if dirname == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if _, ok := dirset[dirname]; ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
dirset[dirname] = struct{}{}
|
|
||||||
allFiles = append(allFiles, &loader.EmbedFile{
|
|
||||||
Name: dirname,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(allFiles, func(i, j int) bool {
|
|
||||||
dir1, name1 := path.Split(path.Clean(allFiles[i].Name))
|
|
||||||
dir2, name2 := path.Split(path.Clean(allFiles[j].Name))
|
|
||||||
if dir1 != dir2 {
|
|
||||||
return dir1 < dir2
|
|
||||||
}
|
|
||||||
return name1 < name2
|
|
||||||
})
|
|
||||||
|
|
||||||
// Make the backing array for the []files slice. This is a LLVM global.
|
|
||||||
embedFileStructType := c.getLLVMType(typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem())
|
|
||||||
var fileStructs []llvm.Value
|
|
||||||
for _, file := range allFiles {
|
|
||||||
fileStruct := llvm.ConstNull(embedFileStructType)
|
|
||||||
name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]))
|
|
||||||
fileStruct = llvm.ConstInsertValue(fileStruct, name, []uint32{0}) // "name" field
|
|
||||||
if file.Hash != "" {
|
|
||||||
data := c.getEmbedFileString(file)
|
|
||||||
fileStruct = llvm.ConstInsertValue(fileStruct, data, []uint32{1}) // "data" field
|
|
||||||
}
|
|
||||||
fileStructs = append(fileStructs, fileStruct)
|
|
||||||
}
|
|
||||||
sliceDataInitializer := llvm.ConstArray(embedFileStructType, fileStructs)
|
|
||||||
sliceDataGlobal := llvm.AddGlobal(c.mod, sliceDataInitializer.Type(), c.pkg.Path()+"$embedfsfiles")
|
|
||||||
sliceDataGlobal.SetInitializer(sliceDataInitializer)
|
|
||||||
sliceDataGlobal.SetLinkage(llvm.InternalLinkage)
|
|
||||||
sliceDataGlobal.SetGlobalConstant(true)
|
|
||||||
sliceDataGlobal.SetUnnamedAddr(true)
|
|
||||||
sliceDataGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceDataInitializer.Type()))
|
|
||||||
|
|
||||||
// Create the slice object itself.
|
|
||||||
// Because embed.FS refers to it as *[]embed.file instead of a plain
|
|
||||||
// []embed.file, we have to store this as a global.
|
|
||||||
slicePtr := llvm.ConstInBoundsGEP(sliceDataGlobal, []llvm.Value{
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
})
|
|
||||||
sliceLen := llvm.ConstInt(c.uintptrType, uint64(len(fileStructs)), false)
|
|
||||||
sliceInitializer := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false)
|
|
||||||
sliceGlobal := llvm.AddGlobal(c.mod, sliceInitializer.Type(), c.pkg.Path()+"$embedfsslice")
|
|
||||||
sliceGlobal.SetInitializer(sliceInitializer)
|
|
||||||
sliceGlobal.SetLinkage(llvm.InternalLinkage)
|
|
||||||
sliceGlobal.SetGlobalConstant(true)
|
|
||||||
sliceGlobal.SetUnnamedAddr(true)
|
|
||||||
sliceGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceInitializer.Type()))
|
|
||||||
|
|
||||||
// Define the embed.FS struct. It has only one field: the files (as a
|
|
||||||
// *[]embed.file).
|
|
||||||
globalInitializer := llvm.ConstNull(c.getLLVMType(member.Type().(*types.Pointer).Elem()))
|
|
||||||
globalInitializer = llvm.ConstInsertValue(globalInitializer, sliceGlobal, []uint32{0})
|
|
||||||
global.SetInitializer(globalInitializer)
|
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
|
||||||
global.SetAlignment(c.targetData.ABITypeAlignment(globalInitializer.Type()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEmbedFileString returns the (constant) string object with the contents of
|
|
||||||
// the given file. This is a llvm.Value of a regular Go string.
|
|
||||||
func (c *compilerContext) getEmbedFileString(file *loader.EmbedFile) llvm.Value {
|
|
||||||
dataGlobalName := "embed/file_" + file.Hash
|
|
||||||
dataGlobal := c.mod.NamedGlobal(dataGlobalName)
|
|
||||||
if dataGlobal.IsNil() {
|
|
||||||
dataGlobalType := llvm.ArrayType(c.ctx.Int8Type(), int(file.Size))
|
|
||||||
dataGlobal = llvm.AddGlobal(c.mod, dataGlobalType, dataGlobalName)
|
|
||||||
}
|
|
||||||
strPtr := llvm.ConstInBoundsGEP(dataGlobal, []llvm.Value{
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
llvm.ConstInt(c.uintptrType, 0, false),
|
|
||||||
})
|
|
||||||
strLen := llvm.ConstInt(c.uintptrType, file.Size, false)
|
|
||||||
return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start defining a function so that it can be filled with instructions: load
|
|
||||||
// parameters, create basic blocks, and set up debug information.
|
|
||||||
// This is separated out from createFunction() so that it is also usable to
|
|
||||||
// define compiler intrinsics like the atomic operations in sync/atomic.
|
|
||||||
func (b *builder) createFunctionStart(intrinsic bool) {
|
|
||||||
if b.DumpSSA {
|
if b.DumpSSA {
|
||||||
fmt.Printf("\nfunc %s:\n", b.fn)
|
fmt.Printf("\nfunc %s:\n", b.fn)
|
||||||
}
|
}
|
||||||
@@ -1043,17 +859,9 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
b.addError(b.fn.Pos(), errValue)
|
b.addError(b.fn.Pos(), errValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b.addStandardDefinedAttributes(b.llvmFn)
|
b.addStandardDefinedAttributes(b.llvmFn)
|
||||||
if !b.info.exported {
|
if !b.info.exported {
|
||||||
// Do not set visibility for local linkage (internal or private).
|
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||||
// Otherwise a "local linkage requires default visibility"
|
|
||||||
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
|
|
||||||
// is thrown.
|
|
||||||
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
|
|
||||||
b.llvmFn.Linkage() != llvm.PrivateLinkage {
|
|
||||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
|
||||||
}
|
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
}
|
}
|
||||||
if b.info.section != "" {
|
if b.info.section != "" {
|
||||||
@@ -1103,21 +911,12 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pre-create all basic blocks in the function.
|
// Pre-create all basic blocks in the function.
|
||||||
var entryBlock llvm.BasicBlock
|
for _, block := range b.fn.DomPreorder() {
|
||||||
if intrinsic {
|
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
||||||
// This function isn't defined in Go SSA. It is probably a compiler
|
b.blockEntries[block] = llvmBlock
|
||||||
// intrinsic (like an atomic operation). Create the entry block
|
b.blockExits[block] = llvmBlock
|
||||||
// manually.
|
|
||||||
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
|
|
||||||
} else {
|
|
||||||
for _, block := range b.fn.DomPreorder() {
|
|
||||||
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
|
|
||||||
b.blockEntries[block] = llvmBlock
|
|
||||||
b.blockExits[block] = llvmBlock
|
|
||||||
}
|
|
||||||
// Normal functions have an entry block.
|
|
||||||
entryBlock = b.blockEntries[b.fn.Blocks[0]]
|
|
||||||
}
|
}
|
||||||
|
entryBlock := b.blockEntries[b.fn.Blocks[0]]
|
||||||
b.SetInsertPointAtEnd(entryBlock)
|
b.SetInsertPointAtEnd(entryBlock)
|
||||||
|
|
||||||
if b.fn.Synthetic == "package initializer" {
|
if b.fn.Synthetic == "package initializer" {
|
||||||
@@ -1153,10 +952,10 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
} else {
|
} else {
|
||||||
fieldOffsets := b.expandFormalParamOffsets(llvmType)
|
fieldOffsets := b.expandFormalParamOffsets(llvmType)
|
||||||
for i, field := range fields {
|
for i, field := range fields {
|
||||||
expr := b.dibuilder.CreateExpression([]uint64{
|
expr := b.dibuilder.CreateExpression([]int64{
|
||||||
0x1000, // DW_OP_LLVM_fragment
|
0x1000, // DW_OP_LLVM_fragment
|
||||||
fieldOffsets[i] * 8, // offset in bits
|
int64(fieldOffsets[i]) * 8, // offset in bits
|
||||||
b.targetData.TypeAllocSize(field.Type()) * 8, // size in bits
|
int64(b.targetData.TypeAllocSize(field.Type())) * 8, // size in bits
|
||||||
})
|
})
|
||||||
b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
|
b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
|
||||||
}
|
}
|
||||||
@@ -1192,13 +991,6 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
// them.
|
// them.
|
||||||
b.deferInitFunc()
|
b.deferInitFunc()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// createFunction builds the LLVM IR implementation for this function. The
|
|
||||||
// function must not yet be defined, otherwise this function will create a
|
|
||||||
// diagnostic.
|
|
||||||
func (b *builder) createFunction() {
|
|
||||||
b.createFunctionStart(false)
|
|
||||||
|
|
||||||
// Fill blocks with instructions.
|
// Fill blocks with instructions.
|
||||||
for _, block := range b.fn.DomPreorder() {
|
for _, block := range b.fn.DomPreorder() {
|
||||||
@@ -1246,12 +1038,6 @@ func (b *builder) createFunction() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.hasDeferFrame() {
|
|
||||||
// Create the landing pad block, where execution continues after a
|
|
||||||
// panic.
|
|
||||||
b.createLandingPad()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve phi nodes
|
// Resolve phi nodes
|
||||||
for _, phi := range b.phis {
|
for _, phi := range b.phis {
|
||||||
block := phi.ssa.Block()
|
block := phi.ssa.Block()
|
||||||
@@ -1277,7 +1063,6 @@ func (b *builder) createFunction() {
|
|||||||
// Create anonymous functions (closures etc.).
|
// Create anonymous functions (closures etc.).
|
||||||
for _, sub := range b.fn.AnonFuncs {
|
for _, sub := range b.fn.AnonFuncs {
|
||||||
b := newBuilder(b.compilerContext, b.Builder, sub)
|
b := newBuilder(b.compilerContext, b.Builder, sub)
|
||||||
b.llvmFn.SetLinkage(llvm.InternalLinkage)
|
|
||||||
b.createFunction()
|
b.createFunction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1380,12 +1165,9 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
|||||||
b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
|
b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
|
||||||
case *ssa.Panic:
|
case *ssa.Panic:
|
||||||
value := b.getValue(instr.X)
|
value := b.getValue(instr.X)
|
||||||
b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
|
b.createRuntimeCall("_panic", []llvm.Value{value}, "")
|
||||||
b.CreateUnreachable()
|
b.CreateUnreachable()
|
||||||
case *ssa.Return:
|
case *ssa.Return:
|
||||||
if b.hasDeferFrame() {
|
|
||||||
b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "")
|
|
||||||
}
|
|
||||||
if len(instr.Results) == 0 {
|
if len(instr.Results) == 0 {
|
||||||
b.CreateRetVoid()
|
b.CreateRetVoid()
|
||||||
} else if len(instr.Results) == 1 {
|
} else if len(instr.Results) == 1 {
|
||||||
@@ -1446,7 +1228,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
case "cap":
|
case "cap":
|
||||||
value := argValues[0]
|
value := argValues[0]
|
||||||
var llvmCap llvm.Value
|
var llvmCap llvm.Value
|
||||||
switch argTypes[0].Underlying().(type) {
|
switch argTypes[0].(type) {
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
|
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
@@ -1562,12 +1344,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
ptrValue := b.CreatePtrToInt(value, b.uintptrType, "")
|
ptrValue := b.CreatePtrToInt(value, b.uintptrType, "")
|
||||||
b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "")
|
b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "")
|
||||||
case *types.Slice:
|
|
||||||
bufptr := b.CreateExtractValue(value, 0, "")
|
|
||||||
buflen := b.CreateExtractValue(value, 1, "")
|
|
||||||
bufcap := b.CreateExtractValue(value, 2, "")
|
|
||||||
ptrValue := b.CreatePtrToInt(bufptr, b.uintptrType, "")
|
|
||||||
b.createRuntimeCall("printslice", []llvm.Value{ptrValue, buflen, bufcap}, "")
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, b.makeError(pos, "unknown arg type: "+typ.String())
|
return llvm.Value{}, b.makeError(pos, "unknown arg type: "+typ.String())
|
||||||
}
|
}
|
||||||
@@ -1580,13 +1356,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
cplx := argValues[0]
|
cplx := argValues[0]
|
||||||
return b.CreateExtractValue(cplx, 0, "real"), nil
|
return b.CreateExtractValue(cplx, 0, "real"), nil
|
||||||
case "recover":
|
case "recover":
|
||||||
useParentFrame := uint64(0)
|
return b.createRuntimeCall("_recover", nil, ""), nil
|
||||||
if b.hasDeferFrame() {
|
|
||||||
// recover() should return the panic value of the parent function,
|
|
||||||
// not of the current function.
|
|
||||||
useParentFrame = 1
|
|
||||||
}
|
|
||||||
return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil
|
|
||||||
case "ssa:wrapnilchk":
|
case "ssa:wrapnilchk":
|
||||||
// TODO: do an actual nil check?
|
// TODO: do an actual nil check?
|
||||||
return argValues[0], nil
|
return argValues[0], nil
|
||||||
@@ -1598,20 +1368,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
ptr := argValues[0]
|
ptr := argValues[0]
|
||||||
len := argValues[1]
|
len := argValues[1]
|
||||||
return b.CreateGEP(ptr, []llvm.Value{len}, ""), nil
|
return b.CreateGEP(ptr, []llvm.Value{len}, ""), nil
|
||||||
case "Alignof": // unsafe.Alignof
|
|
||||||
align := b.targetData.ABITypeAlignment(argValues[0].Type())
|
|
||||||
return llvm.ConstInt(b.uintptrType, uint64(align), false), nil
|
|
||||||
case "Offsetof": // unsafe.Offsetof
|
|
||||||
// This builtin is a bit harder to implement and may need a bit of
|
|
||||||
// refactoring to work (it may be easier to implement if we have access
|
|
||||||
// to the underlying Go SSA instruction). It is also rarely used: it
|
|
||||||
// only applies in generic code and unsafe.Offsetof isn't very commonly
|
|
||||||
// used anyway.
|
|
||||||
// In other words, postpone it to some other day.
|
|
||||||
return llvm.Value{}, b.makeError(pos, "todo: unsafe.Offsetof")
|
|
||||||
case "Sizeof": // unsafe.Sizeof
|
|
||||||
size := b.targetData.TypeAllocSize(argValues[0].Type())
|
|
||||||
return llvm.ConstInt(b.uintptrType, size, false), nil
|
|
||||||
case "Slice": // unsafe.Slice
|
case "Slice": // unsafe.Slice
|
||||||
// This creates a slice from a pointer and a length.
|
// This creates a slice from a pointer and a length.
|
||||||
// Note that the exception mentioned in the documentation (if the
|
// Note that the exception mentioned in the documentation (if the
|
||||||
@@ -1660,6 +1416,15 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
// applied) function call. If it is anonymous, it may be a closure.
|
// applied) function call. If it is anonymous, it may be a closure.
|
||||||
name := fn.RelString(nil)
|
name := fn.RelString(nil)
|
||||||
switch {
|
switch {
|
||||||
|
case name == "runtime.memcpy" || name == "runtime.memmove" || name == "reflect.memcpy":
|
||||||
|
return b.createMemoryCopyCall(fn, instr.Args)
|
||||||
|
case name == "runtime.memzero":
|
||||||
|
return b.createMemoryZeroCall(instr.Args)
|
||||||
|
case name == "math.Ceil" || name == "math.Floor" || name == "math.Sqrt" || name == "math.Trunc":
|
||||||
|
result, ok := b.createMathOp(instr)
|
||||||
|
if ok {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
|
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
|
||||||
return b.createInlineAsm(instr.Args)
|
return b.createInlineAsm(instr.Args)
|
||||||
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
|
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
|
||||||
@@ -1670,16 +1435,22 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
return b.emitSV64Call(instr.Args)
|
return b.emitSV64Call(instr.Args)
|
||||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||||
return b.emitCSROperation(instr)
|
return b.emitCSROperation(instr)
|
||||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
|
case strings.HasPrefix(name, "syscall.Syscall"):
|
||||||
return b.createSyscall(instr)
|
return b.createSyscall(instr)
|
||||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
|
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
|
||||||
return b.createRawSyscallNoError(instr)
|
return b.createRawSyscallNoError(instr)
|
||||||
case name == "runtime.supportsRecover":
|
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||||
supportsRecover := uint64(0)
|
return b.createVolatileLoad(instr)
|
||||||
if b.supportsRecover() {
|
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||||
supportsRecover = 1
|
return b.createVolatileStore(instr)
|
||||||
|
case strings.HasPrefix(name, "sync/atomic."):
|
||||||
|
val, ok := b.createAtomicOp(instr)
|
||||||
|
if ok {
|
||||||
|
// This call could be lowered as an atomic operation.
|
||||||
|
return val, nil
|
||||||
}
|
}
|
||||||
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
|
// This call couldn't be lowered as an atomic operation, it's
|
||||||
|
// probably something else. Continue as usual.
|
||||||
case name == "runtime/interrupt.New":
|
case name == "runtime/interrupt.New":
|
||||||
return b.createInterruptGlobal(instr)
|
return b.createInterruptGlobal(instr)
|
||||||
}
|
}
|
||||||
@@ -1693,14 +1464,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
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.i8ptrType)
|
||||||
if info.variadic && len(fn.Params) == 0 {
|
|
||||||
// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
|
|
||||||
// Eventually we might be able to eliminate this special case
|
|
||||||
// entirely. For details, see:
|
|
||||||
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
|
|
||||||
fnType := llvm.FunctionType(callee.Type().ElementType().ReturnType(), nil, false)
|
|
||||||
callee = llvm.ConstBitCast(callee, llvm.PointerType(fnType, 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
|
||||||
// example: immediately applied functions.
|
// example: immediately applied functions.
|
||||||
@@ -1742,7 +1505,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
params = append(params, context)
|
params = append(params, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.createInvoke(callee, params, ""), nil
|
return b.createCall(callee, params, ""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getValue returns the LLVM value of a constant, function value, global, or
|
// getValue returns the LLVM value of a constant, function value, global, or
|
||||||
@@ -1786,11 +1549,7 @@ func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 {
|
|||||||
// Determine the maximum allowed size for a slice. The biggest possible
|
// Determine the maximum allowed size for a slice. The biggest possible
|
||||||
// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
|
// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
|
||||||
// divide by the element type to get the real maximum size.
|
// divide by the element type to get the real maximum size.
|
||||||
elementSize := c.targetData.TypeAllocSize(elementType)
|
maxSize := maxPointerValue / c.targetData.TypeAllocSize(elementType)
|
||||||
if elementSize == 0 {
|
|
||||||
elementSize = 1
|
|
||||||
}
|
|
||||||
maxSize := maxPointerValue / elementSize
|
|
||||||
|
|
||||||
// len(slice) is an int. Make sure the length remains small enough to fit in
|
// len(slice) is an int. Make sure the length remains small enough to fit in
|
||||||
// an int.
|
// an int.
|
||||||
@@ -1812,9 +1571,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
switch expr := expr.(type) {
|
switch expr := expr.(type) {
|
||||||
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)
|
if expr.Heap {
|
||||||
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
|
size := b.targetData.TypeAllocSize(typ)
|
||||||
if expr.Heap || size > 256 {
|
|
||||||
// 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 {
|
||||||
@@ -2693,41 +2451,42 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createConst creates a LLVM constant value from a Go constant.
|
// createConst creates a LLVM constant value from a Go constant.
|
||||||
func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
func (b *builder) createConst(expr *ssa.Const) llvm.Value {
|
||||||
switch typ := expr.Type().Underlying().(type) {
|
switch typ := expr.Type().Underlying().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
llvmType := c.getLLVMType(typ)
|
llvmType := b.getLLVMType(typ)
|
||||||
if typ.Info()&types.IsBoolean != 0 {
|
if typ.Info()&types.IsBoolean != 0 {
|
||||||
|
b := constant.BoolVal(expr.Value)
|
||||||
n := uint64(0)
|
n := uint64(0)
|
||||||
if constant.BoolVal(expr.Value) {
|
if b {
|
||||||
n = 1
|
n = 1
|
||||||
}
|
}
|
||||||
return llvm.ConstInt(llvmType, n, false)
|
return llvm.ConstInt(llvmType, n, false)
|
||||||
} else if typ.Info()&types.IsString != 0 {
|
} else if typ.Info()&types.IsString != 0 {
|
||||||
str := constant.StringVal(expr.Value)
|
str := constant.StringVal(expr.Value)
|
||||||
strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false)
|
strLen := llvm.ConstInt(b.uintptrType, uint64(len(str)), false)
|
||||||
var strPtr llvm.Value
|
var strPtr llvm.Value
|
||||||
if str != "" {
|
if str != "" {
|
||||||
objname := c.pkg.Path() + "$string"
|
objname := b.pkg.Path() + "$string"
|
||||||
global := llvm.AddGlobal(c.mod, llvm.ArrayType(c.ctx.Int8Type(), len(str)), objname)
|
global := llvm.AddGlobal(b.mod, llvm.ArrayType(b.ctx.Int8Type(), len(str)), objname)
|
||||||
global.SetInitializer(c.ctx.ConstString(str, false))
|
global.SetInitializer(b.ctx.ConstString(str, false))
|
||||||
global.SetLinkage(llvm.InternalLinkage)
|
global.SetLinkage(llvm.InternalLinkage)
|
||||||
global.SetGlobalConstant(true)
|
global.SetGlobalConstant(true)
|
||||||
global.SetUnnamedAddr(true)
|
global.SetUnnamedAddr(true)
|
||||||
global.SetAlignment(1)
|
global.SetAlignment(1)
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
strPtr = llvm.ConstInBoundsGEP(global, []llvm.Value{zero, zero})
|
strPtr = b.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "")
|
||||||
} else {
|
} else {
|
||||||
strPtr = llvm.ConstNull(c.i8ptrType)
|
strPtr = llvm.ConstNull(b.i8ptrType)
|
||||||
}
|
}
|
||||||
strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen})
|
strObj := llvm.ConstNamedStruct(b.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(b.uintptrType, value, false), b.i8ptrType)
|
||||||
}
|
}
|
||||||
return llvm.ConstNull(c.i8ptrType)
|
return llvm.ConstNull(b.i8ptrType)
|
||||||
} 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)
|
||||||
@@ -2738,18 +2497,18 @@ func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
|||||||
n, _ := constant.Float64Val(expr.Value)
|
n, _ := constant.Float64Val(expr.Value)
|
||||||
return llvm.ConstFloat(llvmType, n)
|
return llvm.ConstFloat(llvmType, n)
|
||||||
} else if typ.Kind() == types.Complex64 {
|
} else if typ.Kind() == types.Complex64 {
|
||||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
|
r := b.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
|
||||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
|
i := b.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
|
||||||
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false))
|
cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false))
|
||||||
cplx = llvm.ConstInsertValue(cplx, r, []uint32{0})
|
cplx = b.CreateInsertValue(cplx, r, 0, "")
|
||||||
cplx = llvm.ConstInsertValue(cplx, i, []uint32{1})
|
cplx = b.CreateInsertValue(cplx, i, 1, "")
|
||||||
return cplx
|
return cplx
|
||||||
} else if typ.Kind() == types.Complex128 {
|
} else if typ.Kind() == types.Complex128 {
|
||||||
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
|
r := b.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
|
||||||
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
|
i := b.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
|
||||||
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false))
|
cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false))
|
||||||
cplx = llvm.ConstInsertValue(cplx, r, []uint32{0})
|
cplx = b.CreateInsertValue(cplx, r, 0, "")
|
||||||
cplx = llvm.ConstInsertValue(cplx, i, []uint32{1})
|
cplx = b.CreateInsertValue(cplx, i, 1, "")
|
||||||
return cplx
|
return cplx
|
||||||
} else {
|
} else {
|
||||||
panic("unknown constant of basic type: " + expr.String())
|
panic("unknown constant of basic type: " + expr.String())
|
||||||
@@ -2758,35 +2517,35 @@ func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
|||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil chan constant")
|
panic("expected nil chan constant")
|
||||||
}
|
}
|
||||||
return llvm.ConstNull(c.getLLVMType(expr.Type()))
|
return llvm.ConstNull(b.getLLVMType(expr.Type()))
|
||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil signature constant")
|
panic("expected nil signature constant")
|
||||||
}
|
}
|
||||||
return llvm.ConstNull(c.getLLVMType(expr.Type()))
|
return llvm.ConstNull(b.getLLVMType(expr.Type()))
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil interface constant")
|
panic("expected nil interface constant")
|
||||||
}
|
}
|
||||||
// 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(b.uintptrType, 0, false),
|
||||||
llvm.ConstPointerNull(c.i8ptrType),
|
llvm.ConstPointerNull(b.i8ptrType),
|
||||||
}
|
}
|
||||||
return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields)
|
return llvm.ConstNamedStruct(b.getLLVMRuntimeType("_interface"), fields)
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil pointer constant")
|
panic("expected nil pointer constant")
|
||||||
}
|
}
|
||||||
return llvm.ConstPointerNull(c.getLLVMType(typ))
|
return llvm.ConstPointerNull(b.getLLVMType(typ))
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
panic("expected nil slice constant")
|
panic("expected nil slice constant")
|
||||||
}
|
}
|
||||||
elemType := c.getLLVMType(typ.Elem())
|
elemType := b.getLLVMType(typ.Elem())
|
||||||
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
||||||
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
llvmLen := llvm.ConstInt(b.uintptrType, 0, false)
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := b.ctx.ConstStruct([]llvm.Value{
|
||||||
llvmPtr, // backing array
|
llvmPtr, // backing array
|
||||||
llvmLen, // len
|
llvmLen, // len
|
||||||
llvmLen, // cap
|
llvmLen, // cap
|
||||||
@@ -2797,7 +2556,7 @@ func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
|
|||||||
// I believe this is not allowed by the Go spec.
|
// I believe this is not allowed by the Go spec.
|
||||||
panic("non-nil map constant")
|
panic("non-nil map constant")
|
||||||
}
|
}
|
||||||
llvmType := c.getLLVMType(typ)
|
llvmType := b.getLLVMType(typ)
|
||||||
return llvm.ConstNull(llvmType)
|
return llvm.ConstNull(llvmType)
|
||||||
default:
|
default:
|
||||||
panic("unknown constant: " + expr.String())
|
panic("unknown constant: " + expr.String())
|
||||||
|
|||||||
+41
-10
@@ -3,12 +3,13 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"go/types"
|
"go/types"
|
||||||
"os"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
"github.com/tinygo-org/tinygo/loader"
|
"github.com/tinygo-org/tinygo/loader"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
@@ -27,6 +28,25 @@ type testCase struct {
|
|||||||
func TestCompiler(t *testing.T) {
|
func TestCompiler(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
// Check LLVM version.
|
||||||
|
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("could not parse LLVM version:", llvm.Version)
|
||||||
|
}
|
||||||
|
if llvmMajor < 11 {
|
||||||
|
// It is likely this version needs to be bumped in the future.
|
||||||
|
// The goal is to at least test the LLVM version that's used by default
|
||||||
|
// in TinyGo and (if possible without too many workarounds) also some
|
||||||
|
// previous versions.
|
||||||
|
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine Go minor version (e.g. 16 in go1.16.3).
|
||||||
|
_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("could not read Go version:", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Determine which tests to run, depending on the Go and LLVM versions.
|
// Determine which tests to run, depending on the Go and LLVM versions.
|
||||||
tests := []testCase{
|
tests := []testCase{
|
||||||
{"basic.go", "", ""},
|
{"basic.go", "", ""},
|
||||||
@@ -36,13 +56,21 @@ func TestCompiler(t *testing.T) {
|
|||||||
{"float.go", "", ""},
|
{"float.go", "", ""},
|
||||||
{"interface.go", "", ""},
|
{"interface.go", "", ""},
|
||||||
{"func.go", "", ""},
|
{"func.go", "", ""},
|
||||||
{"defer.go", "cortex-m-qemu", ""},
|
|
||||||
{"pragma.go", "", ""},
|
{"pragma.go", "", ""},
|
||||||
{"goroutine.go", "wasm", "asyncify"},
|
{"goroutine.go", "wasm", "asyncify"},
|
||||||
{"goroutine.go", "cortex-m-qemu", "tasks"},
|
{"goroutine.go", "cortex-m-qemu", "tasks"},
|
||||||
{"channel.go", "", ""},
|
{"channel.go", "", ""},
|
||||||
|
{"intrinsics.go", "cortex-m-qemu", ""},
|
||||||
|
{"intrinsics.go", "wasm", ""},
|
||||||
{"gc.go", "", ""},
|
{"gc.go", "", ""},
|
||||||
}
|
}
|
||||||
|
if llvmMajor >= 12 {
|
||||||
|
tests = append(tests, testCase{"intrinsics.go", "cortex-m-qemu", ""})
|
||||||
|
tests = append(tests, testCase{"intrinsics.go", "wasm", ""})
|
||||||
|
}
|
||||||
|
if goMinor >= 17 {
|
||||||
|
tests = append(tests, testCase{"go1.17.go", "", ""})
|
||||||
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
name := tc.file
|
name := tc.file
|
||||||
@@ -72,24 +100,22 @@ func TestCompiler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
compilerConfig := &Config{
|
compilerConfig := &Config{
|
||||||
Triple: config.Triple(),
|
Triple: config.Triple(),
|
||||||
Features: config.Features(),
|
|
||||||
GOOS: config.GOOS(),
|
GOOS: config.GOOS(),
|
||||||
GOARCH: config.GOARCH(),
|
GOARCH: config.GOARCH(),
|
||||||
CodeModel: config.CodeModel(),
|
CodeModel: config.CodeModel(),
|
||||||
RelocationModel: config.RelocationModel(),
|
RelocationModel: config.RelocationModel(),
|
||||||
Scheduler: config.Scheduler(),
|
Scheduler: config.Scheduler(),
|
||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.StackSize(),
|
DefaultStackSize: config.Target.DefaultStackSize,
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
}
|
}
|
||||||
machine, err := NewTargetMachine(compilerConfig)
|
machine, err := NewTargetMachine(compilerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to create target machine:", err)
|
t.Fatal("failed to create target machine:", err)
|
||||||
}
|
}
|
||||||
defer machine.Dispose()
|
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, "./testdata/"+tc.file, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, []string{"./testdata/" + tc.file}, config.ClangHeaders, types.Config{
|
||||||
Sizes: Sizes(machine),
|
Sizes: Sizes(machine),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -137,14 +163,14 @@ func TestCompiler(t *testing.T) {
|
|||||||
|
|
||||||
// Update test if needed. Do not check the result.
|
// Update test if needed. Do not check the result.
|
||||||
if *flagUpdate {
|
if *flagUpdate {
|
||||||
err := os.WriteFile(outPath, []byte(mod.String()), 0666)
|
err := ioutil.WriteFile(outPath, []byte(mod.String()), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("failed to write updated output file:", err)
|
t.Error("failed to write updated output file:", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
expected, err := os.ReadFile(outPath)
|
expected, err := ioutil.ReadFile(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to read golden file:", err)
|
t.Fatal("failed to read golden file:", err)
|
||||||
}
|
}
|
||||||
@@ -195,9 +221,14 @@ 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 < 12 && strings.HasPrefix(line, "attributes ") {
|
||||||
|
// Ignore attribute groups. These may change between LLVM versions.
|
||||||
|
// Right now test outputs are for LLVM 12 and higher.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if llvmVersion < 13 && 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 13 and higher.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out = append(out, line)
|
out = append(out, line)
|
||||||
|
|||||||
+28
-201
@@ -15,39 +15,12 @@ package compiler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/types"
|
"go/types"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// supportsRecover returns whether the compiler supports the recover() builtin
|
|
||||||
// for the current architecture.
|
|
||||||
func (b *builder) supportsRecover() bool {
|
|
||||||
switch b.archFamily() {
|
|
||||||
case "wasm32":
|
|
||||||
// Probably needs to be implemented using the exception handling
|
|
||||||
// proposal of WebAssembly:
|
|
||||||
// https://github.com/WebAssembly/exception-handling
|
|
||||||
return false
|
|
||||||
case "riscv64", "xtensa":
|
|
||||||
// TODO: add support for these architectures
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasDeferFrame returns whether the current function needs to catch panics and
|
|
||||||
// run defers.
|
|
||||||
func (b *builder) hasDeferFrame() bool {
|
|
||||||
if b.fn.Recover == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return b.supportsRecover()
|
|
||||||
}
|
|
||||||
|
|
||||||
// deferInitFunc sets up this function for future deferred calls. It must be
|
// deferInitFunc sets up this function for future deferred calls. It must be
|
||||||
// called from within the entry block when this function contains deferred
|
// called from within the entry block when this function contains deferred
|
||||||
// calls.
|
// calls.
|
||||||
@@ -63,151 +36,6 @@ func (b *builder) deferInitFunc() {
|
|||||||
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
||||||
b.deferPtr = b.CreateAlloca(deferType, "deferPtr")
|
b.deferPtr = b.CreateAlloca(deferType, "deferPtr")
|
||||||
b.CreateStore(llvm.ConstPointerNull(deferType), b.deferPtr)
|
b.CreateStore(llvm.ConstPointerNull(deferType), b.deferPtr)
|
||||||
|
|
||||||
if b.hasDeferFrame() {
|
|
||||||
// Set up the defer frame with the current stack pointer.
|
|
||||||
// This assumes that the stack pointer doesn't move outside of the
|
|
||||||
// function prologue/epilogue (an invariant maintained by TinyGo but
|
|
||||||
// possibly broken by the C alloca function).
|
|
||||||
// The frame pointer is _not_ saved, because it is marked as clobbered
|
|
||||||
// in the setjmp-like inline assembly.
|
|
||||||
deferFrameType := b.getLLVMRuntimeType("deferFrame")
|
|
||||||
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
|
|
||||||
stackPointer := b.readStackPointer()
|
|
||||||
b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "")
|
|
||||||
|
|
||||||
// Create the landing pad block, which is where control transfers after
|
|
||||||
// a panic.
|
|
||||||
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// createLandingPad fills in the landing pad block. This block runs the deferred
|
|
||||||
// functions and returns (by jumping to the recover block). If the function is
|
|
||||||
// still panicking after the defers are run, the panic will be re-raised in
|
|
||||||
// destroyDeferFrame.
|
|
||||||
func (b *builder) createLandingPad() {
|
|
||||||
b.SetInsertPointAtEnd(b.landingpad)
|
|
||||||
|
|
||||||
// Add debug info, if needed.
|
|
||||||
// The location used is the closing bracket of the function.
|
|
||||||
if b.Debug {
|
|
||||||
pos := b.program.Fset.Position(b.fn.Syntax().End())
|
|
||||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
|
||||||
}
|
|
||||||
|
|
||||||
b.createRunDefers()
|
|
||||||
|
|
||||||
// Continue at the 'recover' block, which returns to the parent in an
|
|
||||||
// appropriate way.
|
|
||||||
b.CreateBr(b.blockEntries[b.fn.Recover])
|
|
||||||
}
|
|
||||||
|
|
||||||
// createInvokeCheckpoint saves the function state at the given point, to
|
|
||||||
// continue at the landing pad if a panic happened. This is implemented using a
|
|
||||||
// setjmp-like construct.
|
|
||||||
func (b *builder) createInvokeCheckpoint() {
|
|
||||||
// Construct inline assembly equivalents of setjmp.
|
|
||||||
// The assembly works as follows:
|
|
||||||
// * All registers (both callee-saved and caller saved) are clobbered
|
|
||||||
// after the inline assembly returns.
|
|
||||||
// * The assembly stores the address just past the end of the assembly
|
|
||||||
// into the jump buffer.
|
|
||||||
// * The return value (eax, rax, r0, etc) is set to zero in the inline
|
|
||||||
// assembly but set to an unspecified non-zero value when jumping using
|
|
||||||
// a longjmp.
|
|
||||||
var asmString, constraints string
|
|
||||||
resultType := b.uintptrType
|
|
||||||
switch b.archFamily() {
|
|
||||||
case "i386":
|
|
||||||
asmString = `
|
|
||||||
xorl %eax, %eax
|
|
||||||
movl $$1f, 4(%ebx)
|
|
||||||
1:`
|
|
||||||
constraints = "={eax},{ebx},~{ebx},~{ecx},~{edx},~{esi},~{edi},~{ebp},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
|
|
||||||
// This doesn't include the floating point stack because TinyGo uses
|
|
||||||
// newer floating point instructions.
|
|
||||||
case "x86_64":
|
|
||||||
asmString = `
|
|
||||||
leaq 1f(%rip), %rax
|
|
||||||
movq %rax, 8(%rbx)
|
|
||||||
xorq %rax, %rax
|
|
||||||
1:`
|
|
||||||
constraints = "={rax},{rbx},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
|
|
||||||
// This list doesn't include AVX/AVX512 registers because TinyGo
|
|
||||||
// doesn't currently enable support for AVX instructions.
|
|
||||||
case "arm":
|
|
||||||
// Note: the following assembly takes into account that the PC is
|
|
||||||
// always 4 bytes ahead on ARM. The PC that is stored always points
|
|
||||||
// to the instruction just after the assembly fragment so that
|
|
||||||
// tinygo_longjmp lands at the correct instruction.
|
|
||||||
if b.isThumb() {
|
|
||||||
// Instructions are 2 bytes in size.
|
|
||||||
asmString = `
|
|
||||||
movs r0, #0
|
|
||||||
mov r2, pc
|
|
||||||
str r2, [r1, #4]`
|
|
||||||
} else {
|
|
||||||
// Instructions are 4 bytes in size.
|
|
||||||
asmString = `
|
|
||||||
str pc, [r1, #4]
|
|
||||||
movs r0, #0`
|
|
||||||
}
|
|
||||||
constraints = "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"
|
|
||||||
case "aarch64":
|
|
||||||
asmString = `
|
|
||||||
adr x2, 1f
|
|
||||||
str x2, [x1, #8]
|
|
||||||
mov x0, #0
|
|
||||||
1:
|
|
||||||
`
|
|
||||||
constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{vg},~{memory}"
|
|
||||||
if b.GOOS != "darwin" {
|
|
||||||
// These registers cause the following warning when compiling for
|
|
||||||
// MacOS:
|
|
||||||
// warning: inline asm clobber list contains reserved registers:
|
|
||||||
// X18, FP
|
|
||||||
// Reserved registers on the clobber list may not be preserved
|
|
||||||
// across the asm statement, and clobbering them may lead to
|
|
||||||
// undefined behaviour.
|
|
||||||
constraints += ",~{x18},~{fp}"
|
|
||||||
}
|
|
||||||
// TODO: SVE registers, which we don't use in TinyGo at the moment.
|
|
||||||
case "avr":
|
|
||||||
// Note: the Y register (R28:R29) is a fixed register and therefore
|
|
||||||
// needs to be saved manually. TODO: do this only once per function with
|
|
||||||
// a defer frame, not for every call.
|
|
||||||
resultType = b.ctx.Int8Type()
|
|
||||||
asmString = `
|
|
||||||
ldi r24, pm_lo8(1f)
|
|
||||||
ldi r25, pm_hi8(1f)
|
|
||||||
std z+2, r24
|
|
||||||
std z+3, r25
|
|
||||||
std z+4, r28
|
|
||||||
std z+5, r29
|
|
||||||
ldi r24, 0
|
|
||||||
1:`
|
|
||||||
constraints = "={r24},z,~{r0},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r25},~{r26},~{r27}"
|
|
||||||
case "riscv32":
|
|
||||||
asmString = `
|
|
||||||
la a2, 1f
|
|
||||||
sw a2, 4(a1)
|
|
||||||
li a0, 0
|
|
||||||
1:`
|
|
||||||
constraints = "={a0},{a1},~{a1},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{s0},~{s1},~{s2},~{s3},~{s4},~{s5},~{s6},~{s7},~{s8},~{s9},~{s10},~{s11},~{t0},~{t1},~{t2},~{t3},~{t4},~{t5},~{t6},~{ra},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{memory}"
|
|
||||||
default:
|
|
||||||
// This case should have been handled by b.supportsRecover().
|
|
||||||
b.addError(b.fn.Pos(), "unknown architecture for defer: "+b.archFamily())
|
|
||||||
}
|
|
||||||
asmType := llvm.FunctionType(resultType, []llvm.Type{b.deferFrame.Type()}, false)
|
|
||||||
asm := llvm.InlineAsm(asmType, asmString, constraints, false, false, 0, false)
|
|
||||||
result := b.CreateCall(asm, []llvm.Value{b.deferFrame}, "setjmp")
|
|
||||||
result.AddCallSiteAttribute(-1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("returns_twice"), 0))
|
|
||||||
isZero := b.CreateICmp(llvm.IntEQ, result, llvm.ConstInt(resultType, 0, false), "setjmp.result")
|
|
||||||
continueBB := b.insertBasicBlock("")
|
|
||||||
b.CreateCondBr(isZero, continueBB, b.landingpad)
|
|
||||||
b.SetInsertPointAtEnd(continueBB)
|
|
||||||
b.blockExits[b.currentBlock] = continueBB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isInLoop checks if there is a path from a basic block to itself.
|
// isInLoop checks if there is a path from a basic block to itself.
|
||||||
@@ -373,31 +201,30 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a struct out of the collected values to put in the deferred call
|
// Make a struct out of the collected values to put in the defer frame.
|
||||||
// struct.
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferFrame := llvm.ConstNull(deferFrameType)
|
||||||
deferredCall := llvm.ConstNull(deferredCallType)
|
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
deferredCall = b.CreateInsertValue(deferredCall, value, i, "")
|
deferFrame = b.CreateInsertValue(deferFrame, value, i, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put this struct in an allocation.
|
// Put this struct in an allocation.
|
||||||
var alloca llvm.Value
|
var alloca llvm.Value
|
||||||
if !isInLoop(instr.Block()) {
|
if !isInLoop(instr.Block()) {
|
||||||
// This can safely use a stack allocation.
|
// This can safely use a stack allocation.
|
||||||
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
|
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferFrameType, "defer.alloca")
|
||||||
} else {
|
} else {
|
||||||
// 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(deferFrameType)
|
||||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
nilPtr := llvm.ConstNull(b.i8ptrType)
|
nilPtr := llvm.ConstNull(b.i8ptrType)
|
||||||
allocCall := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
|
allocCall := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
|
||||||
alloca = b.CreateBitCast(allocCall, llvm.PointerType(deferredCallType, 0), "defer.alloc")
|
alloca = b.CreateBitCast(allocCall, llvm.PointerType(deferFrameType, 0), "defer.alloc")
|
||||||
}
|
}
|
||||||
if b.NeedsStackObjects {
|
if b.NeedsStackObjects {
|
||||||
b.trackPointer(alloca)
|
b.trackPointer(alloca)
|
||||||
}
|
}
|
||||||
b.CreateStore(deferredCall, alloca)
|
b.CreateStore(deferFrame, 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")
|
allocaCast := b.CreateBitCast(alloca, next.Type(), "defer.alloca.cast")
|
||||||
@@ -421,11 +248,11 @@ func (b *builder) createRunDefers() {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end.
|
// Create loop.
|
||||||
end := b.insertBasicBlock("rundefers.end")
|
loophead := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loophead")
|
||||||
unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default")
|
loop := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loop")
|
||||||
loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop")
|
unreachable := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.default")
|
||||||
loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead")
|
end := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.end")
|
||||||
b.CreateBr(loophead)
|
b.CreateBr(loophead)
|
||||||
|
|
||||||
// Create loop head:
|
// Create loop head:
|
||||||
@@ -457,7 +284,7 @@ func (b *builder) createRunDefers() {
|
|||||||
// Create switch case, for example:
|
// Create switch case, for example:
|
||||||
// case 0:
|
// case 0:
|
||||||
// // run first deferred call
|
// // run first deferred call
|
||||||
block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i))
|
block := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.callback")
|
||||||
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
|
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
|
||||||
b.SetInsertPointAtEnd(block)
|
b.SetInsertPointAtEnd(block)
|
||||||
switch callback := callback.(type) {
|
switch callback := callback.(type) {
|
||||||
@@ -468,7 +295,7 @@ func (b *builder) createRunDefers() {
|
|||||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||||
|
|
||||||
if !callback.IsInvoke() {
|
if !callback.IsInvoke() {
|
||||||
//Expect funcValue to be passed through the deferred call.
|
//Expect funcValue to be passed through the defer frame.
|
||||||
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
|
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
|
||||||
} else {
|
} else {
|
||||||
//Expect typecode
|
//Expect typecode
|
||||||
@@ -479,14 +306,14 @@ func (b *builder) createRunDefers() {
|
|||||||
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
||||||
}
|
}
|
||||||
|
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// 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)
|
||||||
for i := 2; i < len(valueTypes); i++ {
|
for i := 2; i < len(valueTypes); i++ {
|
||||||
gep := b.CreateInBoundsGEP(deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -526,14 +353,14 @@ func (b *builder) createRunDefers() {
|
|||||||
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)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// 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(deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -547,7 +374,7 @@ func (b *builder) createRunDefers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call real function.
|
// Call real function.
|
||||||
b.createInvoke(b.getFunction(callback), forwardParams, "")
|
b.createCall(b.getFunction(callback), forwardParams, "")
|
||||||
|
|
||||||
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.
|
||||||
@@ -558,14 +385,14 @@ func (b *builder) createRunDefers() {
|
|||||||
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.i8ptrType) // closure
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// 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(deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
||||||
forwardParam := b.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
@@ -584,14 +411,14 @@ func (b *builder) createRunDefers() {
|
|||||||
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||||
}
|
}
|
||||||
|
|
||||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferredCallPtr := b.CreateBitCast(deferData, llvm.PointerType(deferredCallType, 0), "defercall")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// 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(deferredCallPtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||||
forwardParam := b.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
argValues = append(argValues, forwardParam)
|
argValues = append(argValues, forwardParam)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,16 +120,16 @@ func (b *builder) createGo(instr *ssa.Go) {
|
|||||||
// createGoroutineStartWrapper creates a wrapper for the task-based
|
// createGoroutineStartWrapper creates a wrapper for the task-based
|
||||||
// implementation of goroutines. For example, to call a function like this:
|
// implementation of goroutines. For example, to call a function like this:
|
||||||
//
|
//
|
||||||
// func add(x, y int) int { ... }
|
// func add(x, y int) int { ... }
|
||||||
//
|
//
|
||||||
// It creates a wrapper like this:
|
// It creates a wrapper like this:
|
||||||
//
|
//
|
||||||
// func add$gowrapper(ptr *unsafe.Pointer) {
|
// func add$gowrapper(ptr *unsafe.Pointer) {
|
||||||
// args := (*struct{
|
// args := (*struct{
|
||||||
// x, y int
|
// x, y int
|
||||||
// })(ptr)
|
// })(ptr)
|
||||||
// add(args.x, args.y)
|
// add(args.x, args.y)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// This is useful because the task-based goroutine start implementation only
|
// This is useful because the task-based goroutine start implementation only
|
||||||
// allows a single (pointer) argument to the newly started goroutine. Also, it
|
// allows a single (pointer) argument to the newly started goroutine. Also, it
|
||||||
|
|||||||
+23
-26
@@ -17,7 +17,7 @@ import (
|
|||||||
// operands or return values. It is useful for trivial instructions, like wfi in
|
// operands or return values. It is useful for trivial instructions, like wfi in
|
||||||
// ARM or sleep in AVR.
|
// ARM or sleep in AVR.
|
||||||
//
|
//
|
||||||
// func Asm(asm string)
|
// func Asm(asm string)
|
||||||
//
|
//
|
||||||
// The provided assembly must be a constant.
|
// The provided assembly must be a constant.
|
||||||
func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
||||||
@@ -31,17 +31,17 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
|||||||
// This is a compiler builtin, which allows assembly to be called in a flexible
|
// This is a compiler builtin, which allows assembly to be called in a flexible
|
||||||
// way.
|
// way.
|
||||||
//
|
//
|
||||||
// func AsmFull(asm string, regs map[string]interface{}) uintptr
|
// func AsmFull(asm string, regs map[string]interface{}) uintptr
|
||||||
//
|
//
|
||||||
// The asm parameter must be a constant string. The regs parameter must be
|
// The asm parameter must be a constant string. The regs parameter must be
|
||||||
// provided immediately. For example:
|
// provided immediately. For example:
|
||||||
//
|
//
|
||||||
// arm.AsmFull(
|
// arm.AsmFull(
|
||||||
// "str {value}, {result}",
|
// "str {value}, {result}",
|
||||||
// map[string]interface{}{
|
// map[string]interface{}{
|
||||||
// "value": 1
|
// "value": 1
|
||||||
// "result": &dest,
|
// "result": &dest,
|
||||||
// })
|
// })
|
||||||
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
|
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||||
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
|
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
|
||||||
registers := map[string]llvm.Value{}
|
registers := map[string]llvm.Value{}
|
||||||
@@ -98,10 +98,7 @@ 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
|
constraints = append(constraints, "*m")
|
||||||
// preparation for opaque pointers.
|
|
||||||
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
|
|
||||||
return s
|
|
||||||
default:
|
default:
|
||||||
err = b.makeError(instr.Pos(), "unknown type in inline assembly for value: "+name)
|
err = b.makeError(instr.Pos(), "unknown type in inline assembly for value: "+name)
|
||||||
return s
|
return s
|
||||||
@@ -132,11 +129,11 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
// This is a compiler builtin which emits an inline SVCall instruction. It can
|
// This is a compiler builtin which emits an inline SVCall instruction. It can
|
||||||
// be one of:
|
// be one of:
|
||||||
//
|
//
|
||||||
// func SVCall0(num uintptr) uintptr
|
// func SVCall0(num uintptr) uintptr
|
||||||
// func SVCall1(num uintptr, a1 interface{}) uintptr
|
// func SVCall1(num uintptr, a1 interface{}) uintptr
|
||||||
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
||||||
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
||||||
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
||||||
//
|
//
|
||||||
// The num parameter must be a constant. All other parameters may be any scalar
|
// The num parameter must be a constant. All other parameters may be any scalar
|
||||||
// value supported by LLVM inline assembly.
|
// value supported by LLVM inline assembly.
|
||||||
@@ -169,11 +166,11 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
|
|||||||
// This is a compiler builtin which emits an inline SVCall instruction. It can
|
// This is a compiler builtin which emits an inline SVCall instruction. It can
|
||||||
// be one of:
|
// be one of:
|
||||||
//
|
//
|
||||||
// func SVCall0(num uintptr) uintptr
|
// func SVCall0(num uintptr) uintptr
|
||||||
// func SVCall1(num uintptr, a1 interface{}) uintptr
|
// func SVCall1(num uintptr, a1 interface{}) uintptr
|
||||||
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
||||||
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
||||||
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
||||||
//
|
//
|
||||||
// The num parameter must be a constant. All other parameters may be any scalar
|
// The num parameter must be a constant. All other parameters may be any scalar
|
||||||
// value supported by LLVM inline assembly.
|
// value supported by LLVM inline assembly.
|
||||||
@@ -206,10 +203,10 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
|
|||||||
|
|
||||||
// This is a compiler builtin which emits CSR instructions. It can be one of:
|
// This is a compiler builtin which emits CSR instructions. It can be one of:
|
||||||
//
|
//
|
||||||
// func (csr CSR) Get() uintptr
|
// func (csr CSR) Get() uintptr
|
||||||
// func (csr CSR) Set(uintptr)
|
// func (csr CSR) Set(uintptr)
|
||||||
// func (csr CSR) SetBits(uintptr) uintptr
|
// func (csr CSR) SetBits(uintptr) uintptr
|
||||||
// func (csr CSR) ClearBits(uintptr) uintptr
|
// func (csr CSR) ClearBits(uintptr) uintptr
|
||||||
//
|
//
|
||||||
// The csr parameter (method receiver) must be a constant. Other parameter can
|
// The csr parameter (method receiver) must be a constant. Other parameter can
|
||||||
// be any value.
|
// be any value.
|
||||||
|
|||||||
+51
-85
@@ -152,27 +152,6 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
|
|||||||
return structGlobal
|
return structGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
var basicTypes = [...]string{
|
|
||||||
types.Bool: "bool",
|
|
||||||
types.Int: "int",
|
|
||||||
types.Int8: "int8",
|
|
||||||
types.Int16: "int16",
|
|
||||||
types.Int32: "int32",
|
|
||||||
types.Int64: "int64",
|
|
||||||
types.Uint: "uint",
|
|
||||||
types.Uint8: "uint8",
|
|
||||||
types.Uint16: "uint16",
|
|
||||||
types.Uint32: "uint32",
|
|
||||||
types.Uint64: "uint64",
|
|
||||||
types.Uintptr: "uintptr",
|
|
||||||
types.Float32: "float32",
|
|
||||||
types.Float64: "float64",
|
|
||||||
types.Complex64: "complex64",
|
|
||||||
types.Complex128: "complex128",
|
|
||||||
types.String: "string",
|
|
||||||
types.UnsafePointer: "unsafe.Pointer",
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTypeCodeName returns a name for this type that can be used in the
|
// getTypeCodeName returns a name for this type that can be used in the
|
||||||
// interface lowering pass to assign type codes as expected by the reflect
|
// interface lowering pass to assign type codes as expected by the reflect
|
||||||
// package. See getTypeCodeNum.
|
// package. See getTypeCodeNum.
|
||||||
@@ -183,7 +162,48 @@ func getTypeCodeName(t types.Type) string {
|
|||||||
case *types.Array:
|
case *types.Array:
|
||||||
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
|
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
return "basic:" + basicTypes[t.Kind()]
|
var kind string
|
||||||
|
switch t.Kind() {
|
||||||
|
case types.Bool:
|
||||||
|
kind = "bool"
|
||||||
|
case types.Int:
|
||||||
|
kind = "int"
|
||||||
|
case types.Int8:
|
||||||
|
kind = "int8"
|
||||||
|
case types.Int16:
|
||||||
|
kind = "int16"
|
||||||
|
case types.Int32:
|
||||||
|
kind = "int32"
|
||||||
|
case types.Int64:
|
||||||
|
kind = "int64"
|
||||||
|
case types.Uint:
|
||||||
|
kind = "uint"
|
||||||
|
case types.Uint8:
|
||||||
|
kind = "uint8"
|
||||||
|
case types.Uint16:
|
||||||
|
kind = "uint16"
|
||||||
|
case types.Uint32:
|
||||||
|
kind = "uint32"
|
||||||
|
case types.Uint64:
|
||||||
|
kind = "uint64"
|
||||||
|
case types.Uintptr:
|
||||||
|
kind = "uintptr"
|
||||||
|
case types.Float32:
|
||||||
|
kind = "float32"
|
||||||
|
case types.Float64:
|
||||||
|
kind = "float64"
|
||||||
|
case types.Complex64:
|
||||||
|
kind = "complex64"
|
||||||
|
case types.Complex128:
|
||||||
|
kind = "complex128"
|
||||||
|
case types.String:
|
||||||
|
kind = "string"
|
||||||
|
case types.UnsafePointer:
|
||||||
|
kind = "unsafeptr"
|
||||||
|
default:
|
||||||
|
panic("unknown basic type: " + t.Name())
|
||||||
|
}
|
||||||
|
return "basic:" + kind
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
return "chan:" + getTypeCodeName(t.Elem())
|
return "chan:" + getTypeCodeName(t.Elem())
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
@@ -389,8 +409,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
// value.
|
// value.
|
||||||
|
|
||||||
prevBlock := b.GetInsertBlock()
|
prevBlock := b.GetInsertBlock()
|
||||||
okBlock := b.insertBasicBlock("typeassert.ok")
|
okBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.ok")
|
||||||
nextBlock := b.insertBasicBlock("typeassert.next")
|
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.next")
|
||||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||||
|
|
||||||
@@ -550,8 +570,8 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
|
|||||||
// internally to match interfaces and to call the correct method on an
|
// internally to match interfaces and to call the correct method on an
|
||||||
// interface. Examples:
|
// interface. Examples:
|
||||||
//
|
//
|
||||||
// String() string
|
// String() string
|
||||||
// Read([]byte) (int, error)
|
// Read([]byte) (int, error)
|
||||||
func methodSignature(method *types.Func) string {
|
func methodSignature(method *types.Func) string {
|
||||||
return method.Name() + signature(method.Type().(*types.Signature))
|
return method.Name() + signature(method.Type().(*types.Signature))
|
||||||
}
|
}
|
||||||
@@ -559,8 +579,8 @@ func methodSignature(method *types.Func) string {
|
|||||||
// Make a readable version of a function (pointer) signature.
|
// Make a readable version of a function (pointer) signature.
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
// () string
|
// () string
|
||||||
// (string, int) (int, error)
|
// (string, int) (int, error)
|
||||||
func signature(sig *types.Signature) string {
|
func signature(sig *types.Signature) string {
|
||||||
s := ""
|
s := ""
|
||||||
if sig.Params().Len() == 0 {
|
if sig.Params().Len() == 0 {
|
||||||
@@ -571,77 +591,23 @@ func signature(sig *types.Signature) string {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
s += ", "
|
s += ", "
|
||||||
}
|
}
|
||||||
s += typestring(sig.Params().At(i).Type())
|
s += sig.Params().At(i).Type().String()
|
||||||
}
|
}
|
||||||
s += ")"
|
s += ")"
|
||||||
}
|
}
|
||||||
if sig.Results().Len() == 0 {
|
if sig.Results().Len() == 0 {
|
||||||
// keep as-is
|
// keep as-is
|
||||||
} else if sig.Results().Len() == 1 {
|
} else if sig.Results().Len() == 1 {
|
||||||
s += " " + typestring(sig.Results().At(0).Type())
|
s += " " + sig.Results().At(0).Type().String()
|
||||||
} else {
|
} else {
|
||||||
s += " ("
|
s += " ("
|
||||||
for i := 0; i < sig.Results().Len(); i++ {
|
for i := 0; i < sig.Results().Len(); i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
s += ", "
|
s += ", "
|
||||||
}
|
}
|
||||||
s += typestring(sig.Results().At(i).Type())
|
s += sig.Results().At(i).Type().String()
|
||||||
}
|
}
|
||||||
s += ")"
|
s += ")"
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// typestring returns a stable (human-readable) type string for the given type
|
|
||||||
// that can be used for interface equality checks. It is almost (but not
|
|
||||||
// exactly) the same as calling t.String(). The main difference is some
|
|
||||||
// normalization around `byte` vs `uint8` for example.
|
|
||||||
func typestring(t types.Type) string {
|
|
||||||
// See: https://github.com/golang/go/blob/master/src/go/types/typestring.go
|
|
||||||
switch t := t.(type) {
|
|
||||||
case *types.Array:
|
|
||||||
return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem())
|
|
||||||
case *types.Basic:
|
|
||||||
return basicTypes[t.Kind()]
|
|
||||||
case *types.Chan:
|
|
||||||
switch t.Dir() {
|
|
||||||
case types.SendRecv:
|
|
||||||
return "chan (" + typestring(t.Elem()) + ")"
|
|
||||||
case types.SendOnly:
|
|
||||||
return "chan<- (" + typestring(t.Elem()) + ")"
|
|
||||||
case types.RecvOnly:
|
|
||||||
return "<-chan (" + typestring(t.Elem()) + ")"
|
|
||||||
default:
|
|
||||||
panic("unknown channel direction")
|
|
||||||
}
|
|
||||||
case *types.Interface:
|
|
||||||
methods := make([]string, t.NumMethods())
|
|
||||||
for i := range methods {
|
|
||||||
method := t.Method(i)
|
|
||||||
methods[i] = method.Name() + signature(method.Type().(*types.Signature))
|
|
||||||
}
|
|
||||||
return "interface{" + strings.Join(methods, ";") + "}"
|
|
||||||
case *types.Map:
|
|
||||||
return "map[" + typestring(t.Key()) + "]" + typestring(t.Elem())
|
|
||||||
case *types.Named:
|
|
||||||
return t.String()
|
|
||||||
case *types.Pointer:
|
|
||||||
return "*" + typestring(t.Elem())
|
|
||||||
case *types.Signature:
|
|
||||||
return "func" + signature(t)
|
|
||||||
case *types.Slice:
|
|
||||||
return "[]" + typestring(t.Elem())
|
|
||||||
case *types.Struct:
|
|
||||||
fields := make([]string, t.NumFields())
|
|
||||||
for i := range fields {
|
|
||||||
field := t.Field(i)
|
|
||||||
fields[i] = field.Name() + " " + typestring(field.Type())
|
|
||||||
if tag := t.Tag(i); tag != "" {
|
|
||||||
fields[i] += " " + strconv.Quote(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "struct{" + strings.Join(fields, ";") + "}"
|
|
||||||
default:
|
|
||||||
panic("unknown type: " + t.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+49
-69
@@ -3,67 +3,36 @@ package compiler
|
|||||||
// This file contains helper functions to create calls to LLVM intrinsics.
|
// This file contains helper functions to create calls to LLVM intrinsics.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/token"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Define unimplemented intrinsic functions.
|
// createMemoryCopyCall creates a call to a builtin LLVM memcpy or memmove
|
||||||
//
|
|
||||||
// Some functions are either normally implemented in Go assembly (like
|
|
||||||
// sync/atomic functions) or intentionally left undefined to be implemented
|
|
||||||
// directly in the compiler (like runtime/volatile functions). Either way, look
|
|
||||||
// for these and implement them if this is the case.
|
|
||||||
func (b *builder) defineIntrinsicFunction() {
|
|
||||||
name := b.fn.RelString(nil)
|
|
||||||
switch {
|
|
||||||
case name == "runtime.memcpy" || name == "runtime.memmove":
|
|
||||||
b.createMemoryCopyImpl()
|
|
||||||
case name == "runtime.memzero":
|
|
||||||
b.createMemoryZeroImpl()
|
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
|
||||||
b.createVolatileLoad()
|
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
|
||||||
b.createVolatileStore()
|
|
||||||
case strings.HasPrefix(name, "sync/atomic.") && token.IsExported(b.fn.Name()):
|
|
||||||
b.createFunctionStart(true)
|
|
||||||
returnValue := b.createAtomicOp(b.fn.Name())
|
|
||||||
if !returnValue.IsNil() {
|
|
||||||
b.CreateRet(returnValue)
|
|
||||||
} else {
|
|
||||||
b.CreateRetVoid()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// createMemoryCopyImpl creates a call to a builtin LLVM memcpy or memmove
|
|
||||||
// function, declaring this function if needed. These calls are treated
|
// function, declaring this function if needed. These calls are treated
|
||||||
// specially by optimization passes possibly resulting in better generated code,
|
// specially by optimization passes possibly resulting in better generated code,
|
||||||
// and will otherwise be lowered to regular libc memcpy/memmove calls.
|
// and will otherwise be lowered to regular libc memcpy/memmove calls.
|
||||||
func (b *builder) createMemoryCopyImpl() {
|
func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm.Value, error) {
|
||||||
b.createFunctionStart(true)
|
fnName := "llvm." + fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||||
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.i8ptrType, b.i8ptrType, 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
|
||||||
for _, param := range b.fn.Params {
|
for _, param := range args {
|
||||||
params = append(params, b.getValue(param))
|
params = append(params, b.getValue(param))
|
||||||
}
|
}
|
||||||
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
|
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
|
||||||
b.CreateCall(llvmFn, params, "")
|
b.CreateCall(llvmFn, params, "")
|
||||||
b.CreateRetVoid()
|
return llvm.Value{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
|
// createMemoryZeroCall creates calls to llvm.memset.* to zero a block of
|
||||||
// memory, declaring the function if needed. These calls will be lowered to
|
// memory, declaring the function if needed. These calls will be lowered to
|
||||||
// regular libc memset calls if they aren't optimized out in a different way.
|
// regular libc memset calls if they aren't optimized out in a different way.
|
||||||
func (b *builder) createMemoryZeroImpl() {
|
func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
|
||||||
b.createFunctionStart(true)
|
|
||||||
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||||
llvmFn := b.mod.NamedFunction(fnName)
|
llvmFn := b.mod.NamedFunction(fnName)
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
@@ -71,54 +40,65 @@ func (b *builder) createMemoryZeroImpl() {
|
|||||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
||||||
}
|
}
|
||||||
params := []llvm.Value{
|
params := []llvm.Value{
|
||||||
b.getValue(b.fn.Params[0]),
|
b.getValue(args[0]),
|
||||||
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
||||||
b.getValue(b.fn.Params[1]),
|
b.getValue(args[1]),
|
||||||
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
|
||||||
}
|
}
|
||||||
b.CreateCall(llvmFn, params, "")
|
b.CreateCall(llvmFn, params, "")
|
||||||
b.CreateRetVoid()
|
return llvm.Value{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var mathToLLVMMapping = map[string]string{
|
var mathToLLVMMapping = map[string]string{
|
||||||
"math.Ceil": "llvm.ceil.f64",
|
|
||||||
"math.Exp": "llvm.exp.f64",
|
|
||||||
"math.Exp2": "llvm.exp2.f64",
|
|
||||||
"math.Floor": "llvm.floor.f64",
|
|
||||||
"math.Log": "llvm.log.f64",
|
|
||||||
"math.Sqrt": "llvm.sqrt.f64",
|
"math.Sqrt": "llvm.sqrt.f64",
|
||||||
|
"math.Floor": "llvm.floor.f64",
|
||||||
|
"math.Ceil": "llvm.ceil.f64",
|
||||||
"math.Trunc": "llvm.trunc.f64",
|
"math.Trunc": "llvm.trunc.f64",
|
||||||
}
|
}
|
||||||
|
|
||||||
// defineMathOp defines a math function body as a call to a LLVM intrinsic,
|
// createMathOp tries to lower the given call as a LLVM math intrinsic, if
|
||||||
// instead of the regular Go implementation. This allows LLVM to reason about
|
// possible. It returns the call result if possible, and a boolean whether it
|
||||||
// the math operation and (depending on the architecture) allows it to lower the
|
// succeeded. If it doesn't succeed, the architecture doesn't support the given
|
||||||
// operation to very fast floating point instructions. If this is not possible,
|
// intrinsic.
|
||||||
// LLVM will emit a call to a libm function that implements the same operation.
|
func (b *builder) createMathOp(call *ssa.CallCommon) (llvm.Value, bool) {
|
||||||
//
|
// Check whether this intrinsic is supported on the given GOARCH.
|
||||||
// One example of an optimization that LLVM can do is to convert
|
// If it is unsupported, this can have two reasons:
|
||||||
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
|
//
|
||||||
// beneficial on architectures where 64-bit floating point operations are (much)
|
// 1. LLVM can expand the intrinsic inline (using float instructions), but
|
||||||
// more expensive than 32-bit ones.
|
// the result doesn't pass the tests of the math package.
|
||||||
func (b *builder) defineMathOp() {
|
// 2. LLVM cannot expand the intrinsic inline, will therefore lower it as a
|
||||||
b.createFunctionStart(true)
|
// libm function call, but the libm function call also fails the math
|
||||||
llvmName := mathToLLVMMapping[b.fn.RelString(nil)]
|
// package tests.
|
||||||
if llvmName == "" {
|
//
|
||||||
panic("unreachable: unknown math operation") // sanity check
|
// Whatever the implementation, it must pass the tests in the math package
|
||||||
|
// so unfortunately only the below intrinsic+architecture combinations are
|
||||||
|
// supported.
|
||||||
|
name := call.StaticCallee().RelString(nil)
|
||||||
|
switch name {
|
||||||
|
case "math.Ceil", "math.Floor", "math.Trunc":
|
||||||
|
if b.GOARCH != "wasm" && b.GOARCH != "arm64" {
|
||||||
|
return llvm.Value{}, false
|
||||||
|
}
|
||||||
|
case "math.Sqrt":
|
||||||
|
if b.GOARCH != "wasm" && b.GOARCH != "amd64" && b.GOARCH != "386" {
|
||||||
|
return llvm.Value{}, false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return llvm.Value{}, false // only the above functions are supported.
|
||||||
}
|
}
|
||||||
llvmFn := b.mod.NamedFunction(llvmName)
|
|
||||||
|
llvmFn := b.mod.NamedFunction(mathToLLVMMapping[name])
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
// The intrinsic doesn't exist yet, so declare it.
|
// The intrinsic doesn't exist yet, so declare it.
|
||||||
// At the moment, all supported intrinsics have the form "double
|
// At the moment, all supported intrinsics have the form "double
|
||||||
// foo(double %x)" so we can hardcode the signature here.
|
// foo(double %x)" so we can hardcode the signature here.
|
||||||
llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
|
llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
|
||||||
llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType)
|
llvmFn = llvm.AddFunction(b.mod, mathToLLVMMapping[name], llvmType)
|
||||||
}
|
}
|
||||||
// Create a call to the intrinsic.
|
// Create a call to the intrinsic.
|
||||||
args := make([]llvm.Value, len(b.fn.Params))
|
args := make([]llvm.Value, len(call.Args))
|
||||||
for i, param := range b.fn.Params {
|
for i, arg := range call.Args {
|
||||||
args[i] = b.getValue(param)
|
args[i] = b.getValue(arg)
|
||||||
}
|
}
|
||||||
result := b.CreateCall(llvmFn, args, "")
|
return b.CreateCall(llvmFn, args, ""), true
|
||||||
b.CreateRet(result)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
|
|||||||
return fmt.Errorf("type %q uses global context", t.String())
|
return fmt.Errorf("type %q uses global context", t.String())
|
||||||
default:
|
default:
|
||||||
// we used some other context by accident
|
// we used some other context by accident
|
||||||
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.String(), t.Context(), c.ctx)
|
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.Context(), c.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a composite type, check the components of the type
|
// if this is a composite type, check the components of the type
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
@@ -24,23 +23,6 @@ func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitca
|
|||||||
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name)
|
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertBasicBlock inserts a new basic block after the current basic block.
|
|
||||||
// This is useful when inserting new basic blocks while converting a
|
|
||||||
// *ssa.BasicBlock to a llvm.BasicBlock and the LLVM basic block needs some
|
|
||||||
// extra blocks.
|
|
||||||
// It does not update b.blockExits, this must be done by the caller.
|
|
||||||
func (b *builder) insertBasicBlock(name string) llvm.BasicBlock {
|
|
||||||
currentBB := b.Builder.GetInsertBlock()
|
|
||||||
nextBB := llvm.NextBasicBlock(currentBB)
|
|
||||||
if nextBB.IsNil() {
|
|
||||||
// Last basic block in the function, so add one to the end.
|
|
||||||
return b.ctx.AddBasicBlock(b.llvmFn, name)
|
|
||||||
}
|
|
||||||
// Insert a basic block before the next basic block - that is, at the
|
|
||||||
// current insert location.
|
|
||||||
return b.ctx.InsertBasicBlock(nextBB, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
|
// emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
|
||||||
// llvm.lifetime.end intrinsic. It is commonly used together with
|
// llvm.lifetime.end intrinsic. It is commonly used together with
|
||||||
// createTemporaryAlloca.
|
// createTemporaryAlloca.
|
||||||
@@ -271,46 +253,3 @@ func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.In
|
|||||||
panic("unknown LLVM type")
|
panic("unknown LLVM type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// archFamily returns the archtecture from the LLVM triple but with some
|
|
||||||
// architecture names ("armv6", "thumbv7m", etc) merged into a single
|
|
||||||
// architecture name ("arm").
|
|
||||||
func (c *compilerContext) archFamily() string {
|
|
||||||
arch := strings.Split(c.Triple, "-")[0]
|
|
||||||
if strings.HasPrefix(arch, "arm64") {
|
|
||||||
return "aarch64"
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
|
|
||||||
return "arm"
|
|
||||||
}
|
|
||||||
return arch
|
|
||||||
}
|
|
||||||
|
|
||||||
// isThumb returns whether we're in ARM or in Thumb mode. It panics if the
|
|
||||||
// features string is not one for an ARM architecture.
|
|
||||||
func (c *compilerContext) isThumb() bool {
|
|
||||||
var isThumb, isNotThumb bool
|
|
||||||
for _, feature := range strings.Split(c.Features, ",") {
|
|
||||||
if feature == "+thumb-mode" {
|
|
||||||
isThumb = true
|
|
||||||
}
|
|
||||||
if feature == "-thumb-mode" {
|
|
||||||
isNotThumb = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isThumb == isNotThumb {
|
|
||||||
panic("unexpected feature flags")
|
|
||||||
}
|
|
||||||
return isThumb
|
|
||||||
}
|
|
||||||
|
|
||||||
// readStackPointer emits a LLVM intrinsic call that returns the current stack
|
|
||||||
// pointer as an *i8.
|
|
||||||
func (b *builder) readStackPointer() llvm.Value {
|
|
||||||
stacksave := b.mod.NamedFunction("llvm.stacksave")
|
|
||||||
if stacksave.IsNil() {
|
|
||||||
fnType := llvm.FunctionType(b.i8ptrType, nil, false)
|
|
||||||
stacksave = llvm.AddFunction(b.mod, "llvm.stacksave", fnType)
|
|
||||||
}
|
|
||||||
return b.CreateCall(stacksave, nil, "")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
|
|||||||
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, bitcast, size llvm.Value) {
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
alloca = CreateEntryBlockAlloca(builder, t, name)
|
alloca = CreateEntryBlockAlloca(builder, t, name)
|
||||||
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
||||||
@@ -47,7 +46,6 @@ func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, n
|
|||||||
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
|
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
|
|
||||||
alloca := CreateEntryBlockAlloca(builder, t, name)
|
alloca := CreateEntryBlockAlloca(builder, t, name)
|
||||||
|
|||||||
@@ -15,9 +15,8 @@ import (
|
|||||||
func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needsStackObjects bool, values []llvm.Value) llvm.Value {
|
func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needsStackObjects bool, values []llvm.Value) llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
||||||
|
|
||||||
valueTypes := make([]llvm.Type, len(values))
|
valueTypes := make([]llvm.Type, len(values))
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
@@ -128,9 +127,8 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
|
|||||||
func EmitPointerUnpack(builder llvm.Builder, mod llvm.Module, ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
|
func EmitPointerUnpack(builder llvm.Builder, mod llvm.Module, ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
defer targetData.Dispose()
|
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
||||||
|
|
||||||
packedType := ctx.StructType(valueTypes, false)
|
packedType := ctx.StructType(valueTypes, false)
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -10,13 +10,6 @@ import (
|
|||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// constants for hashmap algorithms; must match src/runtime/hashmap.go
|
|
||||||
const (
|
|
||||||
hashmapAlgorithmBinary = iota
|
|
||||||
hashmapAlgorithmString
|
|
||||||
hashmapAlgorithmInterface
|
|
||||||
)
|
|
||||||
|
|
||||||
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
||||||
// initializing an appropriately sized object.
|
// initializing an appropriately sized object.
|
||||||
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||||
@@ -24,27 +17,22 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
|||||||
keyType := mapType.Key().Underlying()
|
keyType := mapType.Key().Underlying()
|
||||||
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
||||||
var llvmKeyType llvm.Type
|
var llvmKeyType llvm.Type
|
||||||
var alg uint64 // must match values in src/runtime/hashmap.go
|
|
||||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
// String keys.
|
// String keys.
|
||||||
llvmKeyType = b.getLLVMType(keyType)
|
llvmKeyType = b.getLLVMType(keyType)
|
||||||
alg = hashmapAlgorithmString
|
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
// Trivially comparable keys.
|
// Trivially comparable keys.
|
||||||
llvmKeyType = b.getLLVMType(keyType)
|
llvmKeyType = b.getLLVMType(keyType)
|
||||||
alg = hashmapAlgorithmBinary
|
|
||||||
} else {
|
} else {
|
||||||
// All other keys. Implemented as map[interface{}]valueType for ease of
|
// All other keys. Implemented as map[interface{}]valueType for ease of
|
||||||
// implementation.
|
// implementation.
|
||||||
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
||||||
alg = hashmapAlgorithmInterface
|
|
||||||
}
|
}
|
||||||
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
||||||
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
||||||
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
|
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
|
||||||
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
|
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
|
||||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||||
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
|
|
||||||
if expr.Reserve != nil {
|
if expr.Reserve != nil {
|
||||||
sizeHint = b.getValue(expr.Reserve)
|
sizeHint = b.getValue(expr.Reserve)
|
||||||
var err error
|
var err error
|
||||||
@@ -53,7 +41,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
|||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
|
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint}, "")
|
||||||
return hashmap, nil
|
return hashmap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-5
@@ -45,11 +45,7 @@ func (s *stdSizes) Alignof(T types.Type) int64 {
|
|||||||
if t.Info()&types.IsString != 0 {
|
if t.Info()&types.IsString != 0 {
|
||||||
return s.PtrSize
|
return s.PtrSize
|
||||||
}
|
}
|
||||||
case *types.Signature:
|
|
||||||
// Even though functions in tinygo are 2 pointers, they are not 2 pointer aligned
|
|
||||||
return s.PtrSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a := s.Sizeof(T) // may be 0
|
a := s.Sizeof(T) // may be 0
|
||||||
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
||||||
if a < 1 {
|
if a < 1 {
|
||||||
@@ -152,7 +148,7 @@ func (s *stdSizes) Sizeof(T types.Type) int64 {
|
|||||||
return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign)
|
return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign)
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
return s.PtrSize * 2
|
return s.PtrSize * 2
|
||||||
case *types.Pointer, *types.Chan, *types.Map:
|
case *types.Pointer:
|
||||||
return s.PtrSize
|
return s.PtrSize
|
||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
// Func values in TinyGo are two words in size.
|
// Func values in TinyGo are two words in size.
|
||||||
|
|||||||
+11
-13
@@ -163,20 +163,18 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
|||||||
// External/exported functions may not retain pointer values.
|
// External/exported functions may not retain pointer values.
|
||||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||||
if info.exported {
|
if info.exported {
|
||||||
if c.archFamily() == "wasm32" {
|
// Set the wasm-import-module attribute if the function's module is set.
|
||||||
// We need to add the wasm-import-module and the wasm-import-name
|
if info.module != "" {
|
||||||
// attributes.
|
|
||||||
module := info.module
|
|
||||||
if module == "" {
|
|
||||||
module = "env"
|
|
||||||
}
|
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
|
|
||||||
|
|
||||||
name := info.importName
|
// We need to add the wasm-import-module and the wasm-import-name
|
||||||
if name == "" {
|
wasmImportModuleAttr := c.ctx.CreateStringAttribute("wasm-import-module", info.module)
|
||||||
name = info.linkName
|
llvmFn.AddFunctionAttr(wasmImportModuleAttr)
|
||||||
|
|
||||||
|
// Add the Wasm Import Name, if we are a named wasm import
|
||||||
|
if info.importName != "" {
|
||||||
|
wasmImportNameAttr := c.ctx.CreateStringAttribute("wasm-import-name", info.importName)
|
||||||
|
llvmFn.AddFunctionAttr(wasmImportNameAttr)
|
||||||
}
|
}
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
|
|
||||||
}
|
}
|
||||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||||
@@ -193,7 +191,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
|||||||
// should be created right away.
|
// should be created right away.
|
||||||
// The exception is the package initializer, which does appear in the
|
// The exception is the package initializer, which does appear in the
|
||||||
// *ssa.Package members and so shouldn't be created here.
|
// *ssa.Package members and so shouldn't be created here.
|
||||||
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" {
|
if fn.Synthetic != "" && fn.Synthetic != "package initializer" {
|
||||||
irbuilder := c.ctx.NewBuilder()
|
irbuilder := c.ctx.NewBuilder()
|
||||||
b := newBuilder(c, irbuilder, fn)
|
b := newBuilder(c, irbuilder, fn)
|
||||||
b.createFunction()
|
b.createFunction()
|
||||||
|
|||||||
+34
-1
@@ -16,7 +16,20 @@ import (
|
|||||||
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||||
num := b.getValue(call.Args[0])
|
num := b.getValue(call.Args[0])
|
||||||
switch {
|
switch {
|
||||||
case b.GOARCH == "amd64" && b.GOOS == "linux":
|
case b.GOARCH == "amd64":
|
||||||
|
if b.GOOS == "darwin" {
|
||||||
|
// Darwin adds this magic number to system call numbers:
|
||||||
|
//
|
||||||
|
// > Syscall classes for 64-bit system call entry.
|
||||||
|
// > For 64-bit users, the 32-bit syscall number is partitioned
|
||||||
|
// > with the high-order bits representing the class and low-order
|
||||||
|
// > bits being the syscall number within that class.
|
||||||
|
// > The high-order 32-bits of the 64-bit syscall number are unused.
|
||||||
|
// > All system classes enter the kernel via the syscall instruction.
|
||||||
|
//
|
||||||
|
// Source: https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h
|
||||||
|
num = b.CreateOr(num, llvm.ConstInt(b.uintptrType, 0x2000000, false), "")
|
||||||
|
}
|
||||||
// Sources:
|
// Sources:
|
||||||
// https://stackoverflow.com/a/2538212
|
// https://stackoverflow.com/a/2538212
|
||||||
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
|
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
|
||||||
@@ -166,6 +179,26 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
retval = b.CreateInsertValue(retval, zero, 1, "")
|
retval = b.CreateInsertValue(retval, zero, 1, "")
|
||||||
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||||
return retval, nil
|
return retval, nil
|
||||||
|
case "darwin":
|
||||||
|
syscallResult, err := b.createRawSyscall(call)
|
||||||
|
if err != nil {
|
||||||
|
return syscallResult, err
|
||||||
|
}
|
||||||
|
// Return values: r0, r1 uintptr, err Errno
|
||||||
|
// Pseudocode:
|
||||||
|
// var err uintptr
|
||||||
|
// if syscallResult != 0 {
|
||||||
|
// err = syscallResult
|
||||||
|
// }
|
||||||
|
// return syscallResult, 0, err
|
||||||
|
zero := llvm.ConstInt(b.uintptrType, 0, false)
|
||||||
|
hasError := b.CreateICmp(llvm.IntNE, syscallResult, llvm.ConstInt(b.uintptrType, 0, false), "")
|
||||||
|
errResult := b.CreateSelect(hasError, syscallResult, zero, "syscallError")
|
||||||
|
retval := llvm.Undef(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false))
|
||||||
|
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||||
|
retval = b.CreateInsertValue(retval, zero, 1, "")
|
||||||
|
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||||
|
return retval, nil
|
||||||
case "windows":
|
case "windows":
|
||||||
// On Windows, syscall.Syscall* is basically just a function pointer
|
// On Windows, syscall.Syscall* is basically just a function pointer
|
||||||
// call. This is complicated in gc because of stack switching and the
|
// call. This is complicated in gc because of stack switching and the
|
||||||
|
|||||||
Vendored
+41
-43
@@ -1,41 +1,45 @@
|
|||||||
; ModuleID = 'basic.go'
|
; ModuleID = 'basic.go'
|
||||||
source_filename = "basic.go"
|
source_filename = "basic.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%main.kv = type { float }
|
%main.kv = type { float }
|
||||||
%main.kv.0 = type { i8 }
|
%main.kv.0 = type { i8 }
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = add i32 %x, %y
|
%0 = add i32 %x, %y
|
||||||
ret i32 %0
|
ret i32 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %x, %y
|
%0 = icmp eq i32 %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %y, 0
|
%0 = icmp eq i32 %y, 0
|
||||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||||
|
|
||||||
|
divbyzero.throw: ; preds = %entry
|
||||||
|
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
divbyzero.next: ; preds = %entry
|
divbyzero.next: ; preds = %entry
|
||||||
%1 = icmp eq i32 %y, -1
|
%1 = icmp eq i32 %y, -1
|
||||||
%2 = icmp eq i32 %x, -2147483648
|
%2 = icmp eq i32 %x, -2147483648
|
||||||
@@ -43,35 +47,35 @@ divbyzero.next: ; preds = %entry
|
|||||||
%4 = select i1 %3, i32 1, i32 %y
|
%4 = select i1 %3, i32 1, i32 %y
|
||||||
%5 = sdiv i32 %x, %4
|
%5 = sdiv i32 %x, %4
|
||||||
ret i32 %5
|
ret i32 %5
|
||||||
|
|
||||||
divbyzero.throw: ; preds = %entry
|
|
||||||
call void @runtime.divideByZeroPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.divideByZeroPanic(i8*) #0
|
declare void @runtime.divideByZeroPanic(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %y, 0
|
%0 = icmp eq i32 %y, 0
|
||||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||||
|
|
||||||
|
divbyzero.throw: ; preds = %entry
|
||||||
|
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
divbyzero.next: ; preds = %entry
|
divbyzero.next: ; preds = %entry
|
||||||
%1 = udiv i32 %x, %y
|
%1 = udiv i32 %x, %y
|
||||||
ret i32 %1
|
ret i32 %1
|
||||||
|
|
||||||
divbyzero.throw: ; preds = %entry
|
|
||||||
call void @runtime.divideByZeroPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %y, 0
|
%0 = icmp eq i32 %y, 0
|
||||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||||
|
|
||||||
|
divbyzero.throw: ; preds = %entry
|
||||||
|
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
divbyzero.next: ; preds = %entry
|
divbyzero.next: ; preds = %entry
|
||||||
%1 = icmp eq i32 %y, -1
|
%1 = icmp eq i32 %y, -1
|
||||||
%2 = icmp eq i32 %x, -2147483648
|
%2 = icmp eq i32 %x, -2147483648
|
||||||
@@ -79,83 +83,79 @@ divbyzero.next: ; preds = %entry
|
|||||||
%4 = select i1 %3, i32 1, i32 %y
|
%4 = select i1 %3, i32 1, i32 %y
|
||||||
%5 = srem i32 %x, %4
|
%5 = srem i32 %x, %4
|
||||||
ret i32 %5
|
ret i32 %5
|
||||||
|
|
||||||
divbyzero.throw: ; preds = %entry
|
|
||||||
call void @runtime.divideByZeroPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %y, 0
|
%0 = icmp eq i32 %y, 0
|
||||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||||
|
|
||||||
|
divbyzero.throw: ; preds = %entry
|
||||||
|
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
divbyzero.next: ; preds = %entry
|
divbyzero.next: ; preds = %entry
|
||||||
%1 = urem i32 %x, %y
|
%1 = urem i32 %x, %y
|
||||||
ret i32 %1
|
ret i32 %1
|
||||||
|
|
||||||
divbyzero.throw: ; preds = %entry
|
|
||||||
call void @runtime.divideByZeroPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp oeq float %x, %y
|
%0 = fcmp oeq float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatNE(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatNE(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp une float %x, %y
|
%0 = fcmp une float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatLower(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatLower(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp olt float %x, %y
|
%0 = fcmp olt float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp ole float %x, %y
|
%0 = fcmp ole float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp ogt float %x, %y
|
%0 = fcmp ogt float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fcmp oge float %x, %y
|
%0 = fcmp oge float %x, %y
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context) unnamed_addr #1 {
|
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret float %x.r
|
ret float %x.r
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context) unnamed_addr #1 {
|
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret float %x.i
|
ret float %x.i
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #1 {
|
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fadd float %x.r, %y.r
|
%0 = fadd float %x.r, %y.r
|
||||||
%1 = fadd float %x.i, %y.i
|
%1 = fadd float %x.i, %y.i
|
||||||
@@ -165,7 +165,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #1 {
|
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fsub float %x.r, %y.r
|
%0 = fsub float %x.r, %y.r
|
||||||
%1 = fsub float %x.i, %y.i
|
%1 = fsub float %x.i, %y.i
|
||||||
@@ -175,7 +175,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #1 {
|
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = fmul float %x.r, %y.r
|
%0 = fmul float %x.r, %y.r
|
||||||
%1 = fmul float %x.i, %y.i
|
%1 = fmul float %x.i, %y.i
|
||||||
@@ -189,18 +189,16 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context) unnamed_addr #1 {
|
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @"main.foo$1"(%main.kv.0* null, i8* undef)
|
call void @"main.foo$1"(%main.kv.0* null, i8* undef)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define internal void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
|
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
Vendored
+23
-25
@@ -1,28 +1,28 @@
|
|||||||
; ModuleID = 'channel.go'
|
; ModuleID = 'channel.go'
|
||||||
source_filename = "channel.go"
|
source_filename = "channel.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state", i8* }
|
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||||
%"internal/task.gcData" = type { i8* }
|
%"internal/task.gcData" = type { i8* }
|
||||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||||
%"internal/task.stackState" = type { i32, i32 }
|
%"internal/task.stackState" = type { i32, i32 }
|
||||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||||
%chan.value = alloca i32, align 4
|
%chan.value = alloca i32, align 4
|
||||||
@@ -31,22 +31,22 @@ entry:
|
|||||||
store i32 3, i32* %chan.value, align 4
|
store i32 3, i32* %chan.value, align 4
|
||||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #3
|
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: argmemonly nofree nosync nounwind willreturn
|
; Function Attrs: argmemonly nofree nosync nounwind willreturn
|
||||||
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2
|
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
|
||||||
|
|
||||||
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*) #0
|
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
|
||||||
|
|
||||||
; Function Attrs: argmemonly nofree nosync nounwind willreturn
|
; Function Attrs: argmemonly nofree nosync nounwind willreturn
|
||||||
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2
|
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||||
%chan.value = alloca i32, align 4
|
%chan.value = alloca i32, align 4
|
||||||
@@ -54,41 +54,41 @@ entry:
|
|||||||
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #3
|
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*) #0
|
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%complit = alloca {}, align 8
|
%complit = alloca {}, align 8
|
||||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||||
%0 = bitcast {}* %complit to i8*
|
%0 = bitcast {}* %complit to i8*
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #3
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #3
|
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #3
|
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context) unnamed_addr #1 {
|
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
||||||
%select.send.value = alloca i32, align 4
|
%select.send.value = alloca i32, align 4
|
||||||
@@ -105,7 +105,7 @@ entry:
|
|||||||
%.repack4 = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 1, i32 1
|
%.repack4 = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 1, i32 1
|
||||||
store i8* null, i8** %.repack4, align 4
|
store i8* null, i8** %.repack4, align 4
|
||||||
%select.states = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 0
|
%select.states = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 0
|
||||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef) #3
|
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef) #0
|
||||||
call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %select.states.alloca.bitcast)
|
call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %select.states.alloca.bitcast)
|
||||||
%1 = extractvalue { i32, i1 } %select.result, 0
|
%1 = extractvalue { i32, i1 } %select.result, 0
|
||||||
%2 = icmp eq i32 %1, 0
|
%2 = icmp eq i32 %1, 0
|
||||||
@@ -122,9 +122,7 @@ select.body: ; preds = %select.next
|
|||||||
br label %select.done
|
br label %select.done
|
||||||
}
|
}
|
||||||
|
|
||||||
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*) #0
|
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*)
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { argmemonly nofree nosync nounwind willreturn }
|
||||||
attributes #2 = { argmemonly nofree nosync nounwind willreturn }
|
|
||||||
attributes #3 = { nounwind }
|
|
||||||
|
|||||||
-266
@@ -1,266 +0,0 @@
|
|||||||
; ModuleID = 'defer.go'
|
|
||||||
source_filename = "defer.go"
|
|
||||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
|
||||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
|
||||||
|
|
||||||
%runtime._defer = type { i32, %runtime._defer* }
|
|
||||||
%runtime.deferFrame = type { i8*, i8*, [0 x i8*], %runtime.deferFrame*, i1, %runtime._interface }
|
|
||||||
%runtime._interface = type { i32, i8* }
|
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @main.external(i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden void @main.deferSimple(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%defer.alloca = alloca { i32, %runtime._defer* }, align 4
|
|
||||||
%deferPtr = alloca %runtime._defer*, align 4
|
|
||||||
store %runtime._defer* null, %runtime._defer** %deferPtr, align 4
|
|
||||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
|
||||||
%0 = call i8* @llvm.stacksave()
|
|
||||||
call void @runtime.setupDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* %0, i8* undef) #3
|
|
||||||
%defer.alloca.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 0
|
|
||||||
store i32 0, i32* %defer.alloca.repack, align 4
|
|
||||||
%defer.alloca.repack16 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 1
|
|
||||||
store %runtime._defer* null, %runtime._defer** %defer.alloca.repack16, align 4
|
|
||||||
%1 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }**
|
|
||||||
store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %1, align 4
|
|
||||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
|
||||||
br i1 %setjmp.result, label %2, label %lpad
|
|
||||||
|
|
||||||
2: ; preds = %entry
|
|
||||||
call void @main.external(i8* undef) #3
|
|
||||||
br label %rundefers.loophead
|
|
||||||
|
|
||||||
rundefers.loophead: ; preds = %4, %2
|
|
||||||
%3 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4
|
|
||||||
%stackIsNil = icmp eq %runtime._defer* %3, null
|
|
||||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
|
||||||
|
|
||||||
rundefers.loop: ; preds = %rundefers.loophead
|
|
||||||
%stack.next.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %3, i32 0, i32 1
|
|
||||||
%stack.next = load %runtime._defer*, %runtime._defer** %stack.next.gep, align 4
|
|
||||||
store %runtime._defer* %stack.next, %runtime._defer** %deferPtr, align 4
|
|
||||||
%callback.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %3, i32 0, i32 0
|
|
||||||
%callback = load i32, i32* %callback.gep, align 4
|
|
||||||
switch i32 %callback, label %rundefers.default [
|
|
||||||
i32 0, label %rundefers.callback0
|
|
||||||
]
|
|
||||||
|
|
||||||
rundefers.callback0: ; preds = %rundefers.loop
|
|
||||||
%setjmp1 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result2 = icmp eq i32 %setjmp1, 0
|
|
||||||
br i1 %setjmp.result2, label %4, label %lpad
|
|
||||||
|
|
||||||
4: ; preds = %rundefers.callback0
|
|
||||||
call void @"main.deferSimple$1"(i8* undef)
|
|
||||||
br label %rundefers.loophead
|
|
||||||
|
|
||||||
rundefers.default: ; preds = %rundefers.loop
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
rundefers.end: ; preds = %rundefers.loophead
|
|
||||||
call void @runtime.destroyDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
|
|
||||||
recover: ; preds = %rundefers.end3
|
|
||||||
call void @runtime.destroyDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
|
|
||||||
lpad: ; preds = %rundefers.callback012, %rundefers.callback0, %entry
|
|
||||||
br label %rundefers.loophead6
|
|
||||||
|
|
||||||
rundefers.loophead6: ; preds = %6, %lpad
|
|
||||||
%5 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4
|
|
||||||
%stackIsNil7 = icmp eq %runtime._defer* %5, null
|
|
||||||
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
|
|
||||||
|
|
||||||
rundefers.loop5: ; preds = %rundefers.loophead6
|
|
||||||
%stack.next.gep8 = getelementptr inbounds %runtime._defer, %runtime._defer* %5, i32 0, i32 1
|
|
||||||
%stack.next9 = load %runtime._defer*, %runtime._defer** %stack.next.gep8, align 4
|
|
||||||
store %runtime._defer* %stack.next9, %runtime._defer** %deferPtr, align 4
|
|
||||||
%callback.gep10 = getelementptr inbounds %runtime._defer, %runtime._defer* %5, i32 0, i32 0
|
|
||||||
%callback11 = load i32, i32* %callback.gep10, align 4
|
|
||||||
switch i32 %callback11, label %rundefers.default4 [
|
|
||||||
i32 0, label %rundefers.callback012
|
|
||||||
]
|
|
||||||
|
|
||||||
rundefers.callback012: ; preds = %rundefers.loop5
|
|
||||||
%setjmp14 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result15 = icmp eq i32 %setjmp14, 0
|
|
||||||
br i1 %setjmp.result15, label %6, label %lpad
|
|
||||||
|
|
||||||
6: ; preds = %rundefers.callback012
|
|
||||||
call void @"main.deferSimple$1"(i8* undef)
|
|
||||||
br label %rundefers.loophead6
|
|
||||||
|
|
||||||
rundefers.default4: ; preds = %rundefers.loop5
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
rundefers.end3: ; preds = %rundefers.loophead6
|
|
||||||
br label %recover
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nofree nosync nounwind willreturn
|
|
||||||
declare i8* @llvm.stacksave() #2
|
|
||||||
|
|
||||||
declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define internal void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @runtime.destroyDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*) #0
|
|
||||||
|
|
||||||
declare void @runtime.printint32(i32, i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden void @main.deferMultiple(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%defer.alloca2 = alloca { i32, %runtime._defer* }, align 4
|
|
||||||
%defer.alloca = alloca { i32, %runtime._defer* }, align 4
|
|
||||||
%deferPtr = alloca %runtime._defer*, align 4
|
|
||||||
store %runtime._defer* null, %runtime._defer** %deferPtr, align 4
|
|
||||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
|
||||||
%0 = call i8* @llvm.stacksave()
|
|
||||||
call void @runtime.setupDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* %0, i8* undef) #3
|
|
||||||
%defer.alloca.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 0
|
|
||||||
store i32 0, i32* %defer.alloca.repack, align 4
|
|
||||||
%defer.alloca.repack26 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 1
|
|
||||||
store %runtime._defer* null, %runtime._defer** %defer.alloca.repack26, align 4
|
|
||||||
%1 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }**
|
|
||||||
store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %1, align 4
|
|
||||||
%defer.alloca2.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca2, i32 0, i32 0
|
|
||||||
store i32 1, i32* %defer.alloca2.repack, align 4
|
|
||||||
%defer.alloca2.repack27 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca2, i32 0, i32 1
|
|
||||||
%2 = bitcast %runtime._defer** %defer.alloca2.repack27 to { i32, %runtime._defer* }**
|
|
||||||
store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %2, align 4
|
|
||||||
%3 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }**
|
|
||||||
store { i32, %runtime._defer* }* %defer.alloca2, { i32, %runtime._defer* }** %3, align 4
|
|
||||||
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result = icmp eq i32 %setjmp, 0
|
|
||||||
br i1 %setjmp.result, label %4, label %lpad
|
|
||||||
|
|
||||||
4: ; preds = %entry
|
|
||||||
call void @main.external(i8* undef) #3
|
|
||||||
br label %rundefers.loophead
|
|
||||||
|
|
||||||
rundefers.loophead: ; preds = %7, %6, %4
|
|
||||||
%5 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4
|
|
||||||
%stackIsNil = icmp eq %runtime._defer* %5, null
|
|
||||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
|
||||||
|
|
||||||
rundefers.loop: ; preds = %rundefers.loophead
|
|
||||||
%stack.next.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %5, i32 0, i32 1
|
|
||||||
%stack.next = load %runtime._defer*, %runtime._defer** %stack.next.gep, align 4
|
|
||||||
store %runtime._defer* %stack.next, %runtime._defer** %deferPtr, align 4
|
|
||||||
%callback.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %5, i32 0, i32 0
|
|
||||||
%callback = load i32, i32* %callback.gep, align 4
|
|
||||||
switch i32 %callback, label %rundefers.default [
|
|
||||||
i32 0, label %rundefers.callback0
|
|
||||||
i32 1, label %rundefers.callback1
|
|
||||||
]
|
|
||||||
|
|
||||||
rundefers.callback0: ; preds = %rundefers.loop
|
|
||||||
%setjmp4 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result5 = icmp eq i32 %setjmp4, 0
|
|
||||||
br i1 %setjmp.result5, label %6, label %lpad
|
|
||||||
|
|
||||||
6: ; preds = %rundefers.callback0
|
|
||||||
call void @"main.deferMultiple$1"(i8* undef)
|
|
||||||
br label %rundefers.loophead
|
|
||||||
|
|
||||||
rundefers.callback1: ; preds = %rundefers.loop
|
|
||||||
%setjmp7 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result8 = icmp eq i32 %setjmp7, 0
|
|
||||||
br i1 %setjmp.result8, label %7, label %lpad
|
|
||||||
|
|
||||||
7: ; preds = %rundefers.callback1
|
|
||||||
call void @"main.deferMultiple$2"(i8* undef)
|
|
||||||
br label %rundefers.loophead
|
|
||||||
|
|
||||||
rundefers.default: ; preds = %rundefers.loop
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
rundefers.end: ; preds = %rundefers.loophead
|
|
||||||
call void @runtime.destroyDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
|
|
||||||
recover: ; preds = %rundefers.end9
|
|
||||||
call void @runtime.destroyDeferFrame(%runtime.deferFrame* nonnull %deferframe.buf, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
|
|
||||||
lpad: ; preds = %rundefers.callback122, %rundefers.callback018, %rundefers.callback1, %rundefers.callback0, %entry
|
|
||||||
br label %rundefers.loophead12
|
|
||||||
|
|
||||||
rundefers.loophead12: ; preds = %10, %9, %lpad
|
|
||||||
%8 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4
|
|
||||||
%stackIsNil13 = icmp eq %runtime._defer* %8, null
|
|
||||||
br i1 %stackIsNil13, label %rundefers.end9, label %rundefers.loop11
|
|
||||||
|
|
||||||
rundefers.loop11: ; preds = %rundefers.loophead12
|
|
||||||
%stack.next.gep14 = getelementptr inbounds %runtime._defer, %runtime._defer* %8, i32 0, i32 1
|
|
||||||
%stack.next15 = load %runtime._defer*, %runtime._defer** %stack.next.gep14, align 4
|
|
||||||
store %runtime._defer* %stack.next15, %runtime._defer** %deferPtr, align 4
|
|
||||||
%callback.gep16 = getelementptr inbounds %runtime._defer, %runtime._defer* %8, i32 0, i32 0
|
|
||||||
%callback17 = load i32, i32* %callback.gep16, align 4
|
|
||||||
switch i32 %callback17, label %rundefers.default10 [
|
|
||||||
i32 0, label %rundefers.callback018
|
|
||||||
i32 1, label %rundefers.callback122
|
|
||||||
]
|
|
||||||
|
|
||||||
rundefers.callback018: ; preds = %rundefers.loop11
|
|
||||||
%setjmp20 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result21 = icmp eq i32 %setjmp20, 0
|
|
||||||
br i1 %setjmp.result21, label %9, label %lpad
|
|
||||||
|
|
||||||
9: ; preds = %rundefers.callback018
|
|
||||||
call void @"main.deferMultiple$1"(i8* undef)
|
|
||||||
br label %rundefers.loophead12
|
|
||||||
|
|
||||||
rundefers.callback122: ; preds = %rundefers.loop11
|
|
||||||
%setjmp24 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(%runtime.deferFrame* nonnull %deferframe.buf) #4
|
|
||||||
%setjmp.result25 = icmp eq i32 %setjmp24, 0
|
|
||||||
br i1 %setjmp.result25, label %10, label %lpad
|
|
||||||
|
|
||||||
10: ; preds = %rundefers.callback122
|
|
||||||
call void @"main.deferMultiple$2"(i8* undef)
|
|
||||||
br label %rundefers.loophead12
|
|
||||||
|
|
||||||
rundefers.default10: ; preds = %rundefers.loop11
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
rundefers.end9: ; preds = %rundefers.loophead12
|
|
||||||
br label %recover
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define internal void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define internal void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
call void @runtime.printint32(i32 5, i8* undef) #3
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
|
||||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
|
||||||
attributes #2 = { nofree nosync nounwind willreturn }
|
|
||||||
attributes #3 = { nounwind }
|
|
||||||
attributes #4 = { nounwind returns_twice }
|
|
||||||
Vendored
-20
@@ -1,20 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
func external()
|
|
||||||
|
|
||||||
func deferSimple() {
|
|
||||||
defer func() {
|
|
||||||
print(3)
|
|
||||||
}()
|
|
||||||
external()
|
|
||||||
}
|
|
||||||
|
|
||||||
func deferMultiple() {
|
|
||||||
defer func() {
|
|
||||||
print(3)
|
|
||||||
}()
|
|
||||||
defer func() {
|
|
||||||
print(5)
|
|
||||||
}()
|
|
||||||
external()
|
|
||||||
}
|
|
||||||
Vendored
+13
-14
@@ -1,20 +1,20 @@
|
|||||||
; ModuleID = 'float.go'
|
; ModuleID = 'float.go'
|
||||||
source_filename = "float.go"
|
source_filename = "float.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.f32tou32(float %v, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.f32tou32(float %v, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%positive = fcmp oge float %v, 0.000000e+00
|
%positive = fcmp oge float %v, 0.000000e+00
|
||||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||||
@@ -26,25 +26,25 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.maxu32f(i8* %context) unnamed_addr #1 {
|
define hidden float @main.maxu32f(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret float 0x41F0000000000000
|
ret float 0x41F0000000000000
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.maxu32tof32(i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.maxu32tof32(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret i32 -1
|
ret i32 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context) unnamed_addr #1 {
|
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
|
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = uitofp i32 %v to float
|
%0 = uitofp i32 %v to float
|
||||||
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
||||||
@@ -54,7 +54,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden float @main.f32tou32tof32(float %v, i8* %context) unnamed_addr #1 {
|
define hidden float @main.f32tou32tof32(float %v, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%positive = fcmp oge float %v, 0.000000e+00
|
%positive = fcmp oge float %v, 0.000000e+00
|
||||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||||
@@ -67,7 +67,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.f32tou8(float %v, i8* %context) unnamed_addr #1 {
|
define hidden i8 @main.f32tou8(float %v, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%positive = fcmp oge float %v, 0.000000e+00
|
%positive = fcmp oge float %v, 0.000000e+00
|
||||||
%withinmax = fcmp ole float %v, 2.550000e+02
|
%withinmax = fcmp ole float %v, 2.550000e+02
|
||||||
@@ -79,7 +79,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.f32toi8(float %v, i8* %context) unnamed_addr #1 {
|
define hidden i8 @main.f32toi8(float %v, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%abovemin = fcmp oge float %v, -1.280000e+02
|
%abovemin = fcmp oge float %v, -1.280000e+02
|
||||||
%belowmax = fcmp ole float %v, 1.270000e+02
|
%belowmax = fcmp ole float %v, 1.270000e+02
|
||||||
@@ -92,5 +92,4 @@ entry:
|
|||||||
ret i8 %0
|
ret i8 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
|
|||||||
Vendored
+14
-16
@@ -1,49 +1,47 @@
|
|||||||
; ModuleID = 'func.go'
|
; ModuleID = 'func.go'
|
||||||
source_filename = "func.go"
|
source_filename = "func.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.foo(i8* %callback.context, void ()* %callback.funcptr, i8* %context) unnamed_addr #1 {
|
define hidden void @main.foo(i8* %callback.context, void ()* %callback.funcptr, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq void ()* %callback.funcptr, null
|
%0 = icmp eq void ()* %callback.funcptr, null
|
||||||
br i1 %0, label %fpcall.throw, label %fpcall.next
|
br i1 %0, label %fpcall.throw, label %fpcall.next
|
||||||
|
|
||||||
|
fpcall.throw: ; preds = %entry
|
||||||
|
call void @runtime.nilPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
fpcall.next: ; preds = %entry
|
fpcall.next: ; preds = %entry
|
||||||
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*)*
|
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*)*
|
||||||
call void %1(i32 3, i8* %callback.context) #2
|
call void %1(i32 3, i8* %callback.context) #0
|
||||||
ret void
|
ret void
|
||||||
|
|
||||||
fpcall.throw: ; preds = %entry
|
|
||||||
call void @runtime.nilPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.nilPanic(i8*) #0
|
declare void @runtime.nilPanic(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.bar(i8* %context) unnamed_addr #1 {
|
define hidden void @main.bar(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @main.foo(i8* undef, void ()* bitcast (void (i32, i8*)* @main.someFunc to void ()*), i8* undef)
|
call void @main.foo(i8* undef, void ()* bitcast (void (i32, i8*)* @main.someFunc to void ()*), i8* undef)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.someFunc(i32 %arg0, i8* %context) unnamed_addr #1 {
|
define hidden void @main.someFunc(i32 %arg0, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
Vendored
+44
-46
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'gc.go'
|
; ModuleID = 'gc.go'
|
||||||
source_filename = "gc.go"
|
source_filename = "gc.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||||
@@ -26,91 +26,91 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:complex128", i32 0 }
|
@"reflect/types.type:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:complex128", i32 0 }
|
||||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:complex128", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null, i32 0 }
|
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:complex128", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null, i32 0 }
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.newScalar(i8* %context) unnamed_addr #1 {
|
define hidden void @main.newScalar(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||||
store i8* %new, i8** @main.scalar1, align 4
|
store i8* %new, i8** @main.scalar1, align 4
|
||||||
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||||
store i8* %new1, i8** bitcast (i32** @main.scalar2 to i8**), align 4
|
store i8* %new1, i8** bitcast (i32** @main.scalar2 to i8**), align 4
|
||||||
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||||
store i8* %new2, i8** bitcast (i64** @main.scalar3 to i8**), align 4
|
store i8* %new2, i8** bitcast (i64** @main.scalar3 to i8**), align 4
|
||||||
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
|
||||||
store i8* %new3, i8** bitcast (float** @main.scalar4 to i8**), align 4
|
store i8* %new3, i8** bitcast (float** @main.scalar4 to i8**), align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.newArray(i8* %context) unnamed_addr #1 {
|
define hidden void @main.newArray(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||||
store i8* %new, i8** bitcast ([3 x i8]** @main.array1 to i8**), align 4
|
store i8* %new, i8** bitcast ([3 x i8]** @main.array1 to i8**), align 4
|
||||||
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||||
store i8* %new1, i8** bitcast ([71 x i8]** @main.array2 to i8**), align 4
|
store i8* %new1, i8** bitcast ([71 x i8]** @main.array2 to i8**), align 4
|
||||||
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #2
|
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||||
store i8* %new2, i8** bitcast ([3 x i8*]** @main.array3 to i8**), align 4
|
store i8* %new2, i8** bitcast ([3 x i8*]** @main.array3 to i8**), align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.newStruct(i8* %context) unnamed_addr #1 {
|
define hidden void @main.newStruct(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||||
store i8* %new, i8** bitcast ({}** @main.struct1 to i8**), align 4
|
store i8* %new, i8** bitcast ({}** @main.struct1 to i8**), align 4
|
||||||
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||||
store i8* %new1, i8** bitcast ({ i32, i32 }** @main.struct2 to i8**), align 4
|
store i8* %new1, i8** bitcast ({ i32, i32 }** @main.struct2 to i8**), align 4
|
||||||
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef) #2
|
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||||
store i8* %new2, i8** bitcast ({ i8*, [60 x i32], i8* }** @main.struct3 to i8**), align 4
|
store i8* %new2, i8** bitcast ({ i8*, [60 x i32], i8* }** @main.struct3 to i8**), align 4
|
||||||
%new3 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-0001" to i8*), i8* undef) #2
|
%new3 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-0001" to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
|
||||||
store i8* %new3, i8** bitcast ({ i8*, [61 x i32] }** @main.struct4 to i8**), align 4
|
store i8* %new3, i8** bitcast ({ i8*, [61 x i32] }** @main.struct4 to i8**), align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context) unnamed_addr #1 {
|
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef) #2
|
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef) #0
|
||||||
%0 = bitcast i8* %new to { i8*, void ()* }*
|
%0 = bitcast i8* %new to { i8*, void ()* }*
|
||||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||||
ret { i8*, void ()* }* %0
|
ret { i8*, void ()* }* %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.makeSlice(i8* %context) unnamed_addr #1 {
|
define hidden void @main.makeSlice(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
|
||||||
store i8* %makeslice, i8** getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 0), align 8
|
store i8* %makeslice, i8** getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 0), align 8
|
||||||
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 1), align 4
|
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 1), align 4
|
||||||
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 2), align 8
|
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 2), align 8
|
||||||
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #2
|
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice1, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice1, i8* undef) #0
|
||||||
store i8* %makeslice1, i8** bitcast ({ i32**, i32, i32 }* @main.slice2 to i8**), align 8
|
store i8* %makeslice1, i8** bitcast ({ i32**, i32, i32 }* @main.slice2 to i8**), align 8
|
||||||
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 1), align 4
|
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 1), align 4
|
||||||
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 2), align 8
|
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 2), align 8
|
||||||
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef) #2
|
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice3, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice3, i8* undef) #0
|
||||||
store i8* %makeslice3, i8** bitcast ({ { i8*, i32, i32 }*, i32, i32 }* @main.slice3 to i8**), align 8
|
store i8* %makeslice3, i8** bitcast ({ { i8*, i32, i32 }*, i32, i32 }* @main.slice3 to i8**), align 8
|
||||||
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 1), align 4
|
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 1), align 4
|
||||||
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 2), align 8
|
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 2), align 8
|
||||||
@@ -118,20 +118,18 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context) unnamed_addr #1 {
|
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #2
|
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
%.repack = bitcast i8* %0 to double*
|
%.repack = bitcast i8* %0 to double*
|
||||||
store double %v.r, double* %.repack, align 8
|
store double %v.r, double* %.repack, align 8
|
||||||
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
|
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
|
||||||
%1 = bitcast i8* %.repack1 to double*
|
%1 = bitcast i8* %.repack1 to double*
|
||||||
store double %v.i, double* %1, align 8
|
store double %v.i, double* %1, align 8
|
||||||
%2 = insertvalue %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:complex128" to i32), i8* undef }, i8* %0, 1
|
%2 = insertvalue %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:complex128" to i32), i8* undef }, i8* %0, 1
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
ret %runtime._interface %2
|
ret %runtime._interface %2
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
Vendored
-30
@@ -1,30 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
type Coord interface {
|
|
||||||
int | float32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Point[T Coord] struct {
|
|
||||||
X, Y T
|
|
||||||
}
|
|
||||||
|
|
||||||
func Add[T Coord](a, b Point[T]) Point[T] {
|
|
||||||
checkSize(unsafe.Alignof(a))
|
|
||||||
checkSize(unsafe.Sizeof(a))
|
|
||||||
return Point[T]{
|
|
||||||
X: a.X + b.X,
|
|
||||||
Y: a.Y + b.Y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var af, bf Point[float32]
|
|
||||||
Add(af, bf)
|
|
||||||
|
|
||||||
var ai, bi Point[int]
|
|
||||||
Add(ai, bi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkSize(uintptr)
|
|
||||||
Vendored
-259
@@ -1,259 +0,0 @@
|
|||||||
; ModuleID = 'generics.go'
|
|
||||||
source_filename = "generics.go"
|
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
|
||||||
target triple = "wasm32-unknown-wasi"
|
|
||||||
|
|
||||||
%"main.Point[int]" = type { i32, i32 }
|
|
||||||
%"main.Point[float32]" = type { float, float }
|
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden void @main.main(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%bi = alloca %"main.Point[int]", align 8
|
|
||||||
%ai = alloca %"main.Point[int]", align 8
|
|
||||||
%bf = alloca %"main.Point[float32]", align 8
|
|
||||||
%af = alloca %"main.Point[float32]", align 8
|
|
||||||
%af.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
|
||||||
store float 0.000000e+00, float* %af.repack, align 8
|
|
||||||
%af.repack1 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
|
||||||
store float 0.000000e+00, float* %af.repack1, align 4
|
|
||||||
%0 = bitcast %"main.Point[float32]"* %af to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
|
||||||
%bf.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
|
||||||
store float 0.000000e+00, float* %bf.repack, align 8
|
|
||||||
%bf.repack2 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
|
||||||
store float 0.000000e+00, float* %bf.repack2, align 4
|
|
||||||
%1 = bitcast %"main.Point[float32]"* %bf to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
|
||||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
|
||||||
%.unpack = load float, float* %.elt, align 8
|
|
||||||
%.elt3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
|
||||||
%.unpack4 = load float, float* %.elt3, align 4
|
|
||||||
%.elt5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
|
||||||
%.unpack6 = load float, float* %.elt5, align 8
|
|
||||||
%.elt7 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
|
||||||
%.unpack8 = load float, float* %.elt7, align 4
|
|
||||||
%2 = call %"main.Point[float32]" @"main.Add[float32]"(float %.unpack, float %.unpack4, float %.unpack6, float %.unpack8, i8* undef)
|
|
||||||
%ai.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
|
||||||
store i32 0, i32* %ai.repack, align 8
|
|
||||||
%ai.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
|
||||||
store i32 0, i32* %ai.repack9, align 4
|
|
||||||
%3 = bitcast %"main.Point[int]"* %ai to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %3, i8* undef) #2
|
|
||||||
%bi.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
|
||||||
store i32 0, i32* %bi.repack, align 8
|
|
||||||
%bi.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
|
||||||
store i32 0, i32* %bi.repack10, align 4
|
|
||||||
%4 = bitcast %"main.Point[int]"* %bi to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %4, i8* undef) #2
|
|
||||||
%.elt11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
|
||||||
%.unpack12 = load i32, i32* %.elt11, align 8
|
|
||||||
%.elt13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
|
||||||
%.unpack14 = load i32, i32* %.elt13, align 4
|
|
||||||
%.elt15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
|
||||||
%.unpack16 = load i32, i32* %.elt15, align 8
|
|
||||||
%.elt17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
|
||||||
%.unpack18 = load i32, i32* %.elt17, align 4
|
|
||||||
%5 = call %"main.Point[int]" @"main.Add[int]"(i32 %.unpack12, i32 %.unpack14, i32 %.unpack16, i32 %.unpack18, i8* undef)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%complit = alloca %"main.Point[float32]", align 8
|
|
||||||
%b = alloca %"main.Point[float32]", align 8
|
|
||||||
%a = alloca %"main.Point[float32]", align 8
|
|
||||||
%a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
|
||||||
store float 0.000000e+00, float* %a.repack, align 8
|
|
||||||
%a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
|
||||||
store float 0.000000e+00, float* %a.repack9, align 4
|
|
||||||
%0 = bitcast %"main.Point[float32]"* %a to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
|
||||||
%a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
|
||||||
store float %a.X, float* %a.repack10, align 8
|
|
||||||
%a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
|
||||||
store float %a.Y, float* %a.repack11, align 4
|
|
||||||
%b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
|
||||||
store float 0.000000e+00, float* %b.repack, align 8
|
|
||||||
%b.repack13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
|
||||||
store float 0.000000e+00, float* %b.repack13, align 4
|
|
||||||
%1 = bitcast %"main.Point[float32]"* %b to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
|
||||||
%b.repack14 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
|
||||||
store float %b.X, float* %b.repack14, align 8
|
|
||||||
%b.repack15 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
|
||||||
store float %b.Y, float* %b.repack15, align 4
|
|
||||||
call void @main.checkSize(i32 4, i8* undef) #2
|
|
||||||
call void @main.checkSize(i32 8, i8* undef) #2
|
|
||||||
%complit.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
|
||||||
store float 0.000000e+00, float* %complit.repack, align 8
|
|
||||||
%complit.repack17 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
|
||||||
store float 0.000000e+00, float* %complit.repack17, align 4
|
|
||||||
%2 = bitcast %"main.Point[float32]"* %complit to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
|
||||||
%3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
|
||||||
br i1 false, label %deref.throw, label %deref.next
|
|
||||||
|
|
||||||
deref.next: ; preds = %entry
|
|
||||||
br i1 false, label %deref.throw1, label %deref.next2
|
|
||||||
|
|
||||||
deref.next2: ; preds = %deref.next
|
|
||||||
%4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
|
||||||
%5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
|
||||||
%6 = load float, float* %5, align 8
|
|
||||||
%7 = load float, float* %4, align 8
|
|
||||||
%8 = fadd float %6, %7
|
|
||||||
br i1 false, label %deref.throw3, label %deref.next4
|
|
||||||
|
|
||||||
deref.next4: ; preds = %deref.next2
|
|
||||||
br i1 false, label %deref.throw5, label %deref.next6
|
|
||||||
|
|
||||||
deref.next6: ; preds = %deref.next4
|
|
||||||
%9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
|
||||||
%10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
|
||||||
%11 = load float, float* %10, align 4
|
|
||||||
%12 = load float, float* %9, align 4
|
|
||||||
br i1 false, label %store.throw, label %store.next
|
|
||||||
|
|
||||||
store.next: ; preds = %deref.next6
|
|
||||||
store float %8, float* %3, align 8
|
|
||||||
br i1 false, label %store.throw7, label %store.next8
|
|
||||||
|
|
||||||
store.next8: ; preds = %store.next
|
|
||||||
%13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
|
||||||
%14 = fadd float %11, %12
|
|
||||||
store float %14, float* %13, align 4
|
|
||||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
|
||||||
%.unpack = load float, float* %.elt, align 8
|
|
||||||
%15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
|
|
||||||
%16 = insertvalue %"main.Point[float32]" %15, float %14, 1
|
|
||||||
ret %"main.Point[float32]" %16
|
|
||||||
|
|
||||||
deref.throw: ; preds = %entry
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw1: ; preds = %deref.next
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw3: ; preds = %deref.next2
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw5: ; preds = %deref.next4
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
store.throw: ; preds = %deref.next6
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
store.throw7: ; preds = %store.next
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @main.checkSize(i32, i8*) #0
|
|
||||||
|
|
||||||
declare void @runtime.nilPanic(i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%complit = alloca %"main.Point[int]", align 8
|
|
||||||
%b = alloca %"main.Point[int]", align 8
|
|
||||||
%a = alloca %"main.Point[int]", align 8
|
|
||||||
%a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
|
||||||
store i32 0, i32* %a.repack, align 8
|
|
||||||
%a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
|
||||||
store i32 0, i32* %a.repack9, align 4
|
|
||||||
%0 = bitcast %"main.Point[int]"* %a to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
|
||||||
%a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
|
||||||
store i32 %a.X, i32* %a.repack10, align 8
|
|
||||||
%a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
|
||||||
store i32 %a.Y, i32* %a.repack11, align 4
|
|
||||||
%b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
|
||||||
store i32 0, i32* %b.repack, align 8
|
|
||||||
%b.repack13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
|
||||||
store i32 0, i32* %b.repack13, align 4
|
|
||||||
%1 = bitcast %"main.Point[int]"* %b to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
|
||||||
%b.repack14 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
|
||||||
store i32 %b.X, i32* %b.repack14, align 8
|
|
||||||
%b.repack15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
|
||||||
store i32 %b.Y, i32* %b.repack15, align 4
|
|
||||||
call void @main.checkSize(i32 4, i8* undef) #2
|
|
||||||
call void @main.checkSize(i32 8, i8* undef) #2
|
|
||||||
%complit.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
|
||||||
store i32 0, i32* %complit.repack, align 8
|
|
||||||
%complit.repack17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
|
||||||
store i32 0, i32* %complit.repack17, align 4
|
|
||||||
%2 = bitcast %"main.Point[int]"* %complit to i8*
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
|
||||||
%3 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
|
||||||
br i1 false, label %deref.throw, label %deref.next
|
|
||||||
|
|
||||||
deref.next: ; preds = %entry
|
|
||||||
br i1 false, label %deref.throw1, label %deref.next2
|
|
||||||
|
|
||||||
deref.next2: ; preds = %deref.next
|
|
||||||
%4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
|
||||||
%5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
|
||||||
%6 = load i32, i32* %5, align 8
|
|
||||||
%7 = load i32, i32* %4, align 8
|
|
||||||
%8 = add i32 %6, %7
|
|
||||||
br i1 false, label %deref.throw3, label %deref.next4
|
|
||||||
|
|
||||||
deref.next4: ; preds = %deref.next2
|
|
||||||
br i1 false, label %deref.throw5, label %deref.next6
|
|
||||||
|
|
||||||
deref.next6: ; preds = %deref.next4
|
|
||||||
%9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
|
||||||
%10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
|
||||||
%11 = load i32, i32* %10, align 4
|
|
||||||
%12 = load i32, i32* %9, align 4
|
|
||||||
br i1 false, label %store.throw, label %store.next
|
|
||||||
|
|
||||||
store.next: ; preds = %deref.next6
|
|
||||||
store i32 %8, i32* %3, align 8
|
|
||||||
br i1 false, label %store.throw7, label %store.next8
|
|
||||||
|
|
||||||
store.next8: ; preds = %store.next
|
|
||||||
%13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
|
||||||
%14 = add i32 %11, %12
|
|
||||||
store i32 %14, i32* %13, align 4
|
|
||||||
%.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
|
||||||
%.unpack = load i32, i32* %.elt, align 8
|
|
||||||
%15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
|
|
||||||
%16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
|
|
||||||
ret %"main.Point[int]" %16
|
|
||||||
|
|
||||||
deref.throw: ; preds = %entry
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw1: ; preds = %deref.next
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw3: ; preds = %deref.next2
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
deref.throw5: ; preds = %deref.next4
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
store.throw: ; preds = %deref.next6
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
store.throw7: ; preds = %store.next
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
Vendored
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Test changes to the language introduced in Go 1.17.
|
||||||
|
// For details, see: https://tip.golang.org/doc/go1.17#language
|
||||||
|
// These tests should be merged into the regular slice tests once Go 1.17 is the
|
||||||
|
// minimun Go version for TinyGo.
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
func Add32(p unsafe.Pointer, len int) unsafe.Pointer {
|
||||||
|
return unsafe.Add(p, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add64(p unsafe.Pointer, len int64) unsafe.Pointer {
|
||||||
|
return unsafe.Add(p, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceToArray(s []int) *[4]int {
|
||||||
|
return (*[4]int)(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceToArrayConst() *[4]int {
|
||||||
|
s := make([]int, 6)
|
||||||
|
return (*[4]int)(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceInt(ptr *int, len int) []int {
|
||||||
|
return unsafe.Slice(ptr, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceUint16(ptr *byte, len uint16) []byte {
|
||||||
|
return unsafe.Slice(ptr, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceUint64(ptr *int, len uint64) []int {
|
||||||
|
return unsafe.Slice(ptr, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceInt64(ptr *int, len int64) []int {
|
||||||
|
return unsafe.Slice(ptr, len)
|
||||||
|
}
|
||||||
Vendored
+159
@@ -0,0 +1,159 @@
|
|||||||
|
; ModuleID = 'go1.17.go'
|
||||||
|
source_filename = "go1.17.go"
|
||||||
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = getelementptr i8, i8* %p, i32 %len
|
||||||
|
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||||
|
ret i8* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = trunc i64 %len to i32
|
||||||
|
%1 = getelementptr i8, i8* %p, i32 %0
|
||||||
|
call void @runtime.trackPointer(i8* %1, i8* undef) #0
|
||||||
|
ret i8* %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = icmp ult i32 %s.len, 4
|
||||||
|
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
||||||
|
|
||||||
|
slicetoarray.throw: ; preds = %entry
|
||||||
|
call void @runtime.sliceToArrayPointerPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
slicetoarray.next: ; preds = %entry
|
||||||
|
%1 = bitcast i32* %s.data to [4 x i32]*
|
||||||
|
ret [4 x i32]* %1
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @runtime.sliceToArrayPointerPanic(i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
|
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
|
||||||
|
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||||
|
|
||||||
|
slicetoarray.throw: ; preds = %entry
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
slicetoarray.next: ; preds = %entry
|
||||||
|
%0 = bitcast i8* %makeslice to [4 x i32]*
|
||||||
|
ret [4 x i32]* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = icmp ugt i32 %len, 1073741823
|
||||||
|
%1 = icmp eq i32* %ptr, null
|
||||||
|
%2 = icmp ne i32 %len, 0
|
||||||
|
%3 = and i1 %1, %2
|
||||||
|
%4 = or i1 %3, %0
|
||||||
|
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||||
|
|
||||||
|
unsafe.Slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
unsafe.Slice.next: ; preds = %entry
|
||||||
|
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||||
|
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
|
||||||
|
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
|
||||||
|
%8 = bitcast i32* %ptr to i8*
|
||||||
|
call void @runtime.trackPointer(i8* %8, i8* undef) #0
|
||||||
|
ret { i32*, i32, i32 } %7
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @runtime.unsafeSlicePanic(i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = icmp eq i8* %ptr, null
|
||||||
|
%1 = icmp ne i16 %len, 0
|
||||||
|
%2 = and i1 %0, %1
|
||||||
|
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||||
|
|
||||||
|
unsafe.Slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
unsafe.Slice.next: ; preds = %entry
|
||||||
|
%3 = zext i16 %len to i32
|
||||||
|
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
|
||||||
|
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
|
||||||
|
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
|
||||||
|
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||||
|
ret { i8*, i32, i32 } %6
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = icmp ugt i64 %len, 1073741823
|
||||||
|
%1 = icmp eq i32* %ptr, null
|
||||||
|
%2 = icmp ne i64 %len, 0
|
||||||
|
%3 = and i1 %1, %2
|
||||||
|
%4 = or i1 %3, %0
|
||||||
|
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||||
|
|
||||||
|
unsafe.Slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
unsafe.Slice.next: ; preds = %entry
|
||||||
|
%5 = trunc i64 %len to i32
|
||||||
|
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||||
|
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
||||||
|
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
||||||
|
%9 = bitcast i32* %ptr to i8*
|
||||||
|
call void @runtime.trackPointer(i8* %9, i8* undef) #0
|
||||||
|
ret { i32*, i32, i32 } %8
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = icmp ugt i64 %len, 1073741823
|
||||||
|
%1 = icmp eq i32* %ptr, null
|
||||||
|
%2 = icmp ne i64 %len, 0
|
||||||
|
%3 = and i1 %1, %2
|
||||||
|
%4 = or i1 %3, %0
|
||||||
|
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||||
|
|
||||||
|
unsafe.Slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
unsafe.Slice.next: ; preds = %entry
|
||||||
|
%5 = trunc i64 %len to i32
|
||||||
|
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||||
|
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
||||||
|
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
||||||
|
%9 = bitcast i32* %ptr to i8*
|
||||||
|
call void @runtime.trackPointer(i8* %9, i8* undef) #0
|
||||||
|
ret { i32*, i32, i32 } %8
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { nounwind }
|
||||||
+52
-54
@@ -5,59 +5,59 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
|||||||
|
|
||||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state", i8* }
|
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||||
%"internal/task.gcData" = type {}
|
%"internal/task.gcData" = type {}
|
||||||
%"internal/task.state" = type { i32, i32* }
|
%"internal/task.state" = type { i32, i32* }
|
||||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||||
|
|
||||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef) #8
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef) #0
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @main.regularFunction(i32, i8*) #0
|
declare void @main.regularFunction(i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #2 {
|
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.int = ptrtoint i8* %0 to i32
|
%unpack.int = ptrtoint i8* %0 to i32
|
||||||
call void @main.regularFunction(i32 %unpack.int, i8* undef) #8
|
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*) #0
|
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*)
|
||||||
|
|
||||||
declare void @"internal/task.start"(i32, i8*, i32, i8*) #0
|
declare void @"internal/task.start"(i32, i8*, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef) #8
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #3 {
|
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.int = ptrtoint i8* %0 to i32
|
%unpack.int = ptrtoint i8* %0 to i32
|
||||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
||||||
@@ -65,26 +65,26 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #8
|
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%0 = bitcast i8* %n to i32*
|
%0 = bitcast i8* %n to i32*
|
||||||
store i32 3, i32* %0, align 4
|
store i32 3, i32* %0, align 4
|
||||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #8
|
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
|
||||||
%2 = bitcast i8* %1 to i32*
|
%2 = bitcast i8* %1 to i32*
|
||||||
store i32 5, i32* %2, align 4
|
store i32 5, i32* %2, align 4
|
||||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||||
%4 = bitcast i8* %3 to i8**
|
%4 = bitcast i8* %3 to i8**
|
||||||
store i8* %n, i8** %4, align 4
|
store i8* %n, i8** %4, align 4
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef) #8
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef) #0
|
||||||
%5 = load i32, i32* %0, align 4
|
%5 = load i32, i32* %0, align 4
|
||||||
call void @runtime.printint32(i32 %5, i8* undef) #8
|
call void @runtime.printint32(i32 %5, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.ptr = bitcast i8* %context to i32*
|
%unpack.ptr = bitcast i8* %context to i32*
|
||||||
store i32 7, i32* %unpack.ptr, align 4
|
store i32 7, i32* %unpack.ptr, align 4
|
||||||
@@ -92,7 +92,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #4 {
|
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #3 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
%2 = load i32, i32* %1, align 4
|
%2 = load i32, i32* %1, align 4
|
||||||
@@ -103,12 +103,12 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.printint32(i32, i8*) #0
|
declare void @runtime.printint32(i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #1 {
|
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #8
|
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
store i32 5, i32* %1, align 4
|
store i32 5, i32* %1, align 4
|
||||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||||
@@ -117,13 +117,13 @@ entry:
|
|||||||
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
||||||
%5 = bitcast i8* %4 to void ()**
|
%5 = bitcast i8* %4 to void ()**
|
||||||
store void ()* %fn.funcptr, void ()** %5, align 4
|
store void ()* %fn.funcptr, void ()** %5, align 4
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef) #8
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef) #0
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @main.funcGoroutine.gowrapper(i8* %0) unnamed_addr #5 {
|
define linkonce_odr void @main.funcGoroutine.gowrapper(i8* %0) unnamed_addr #4 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
%2 = load i32, i32* %1, align 4
|
%2 = load i32, i32* %1, align 4
|
||||||
@@ -133,38 +133,38 @@ entry:
|
|||||||
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
||||||
%7 = bitcast i8* %6 to void (i32, i8*)**
|
%7 = bitcast i8* %6 to void (i32, i8*)**
|
||||||
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
||||||
call void %8(i32 %2, i8* %5) #8
|
call void %8(i32 %2, i8* %5) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #1 {
|
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #8
|
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*) #0
|
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #8
|
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*) #0
|
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #8
|
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||||
%1 = bitcast i8* %0 to i8**
|
%1 = bitcast i8* %0 to i8**
|
||||||
store i8* %itf.value, i8** %1, align 4
|
store i8* %itf.value, i8** %1, align 4
|
||||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||||
@@ -176,15 +176,15 @@ entry:
|
|||||||
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
||||||
%5 = bitcast i8* %4 to i32*
|
%5 = bitcast i8* %4 to i32*
|
||||||
store i32 %itf.typecode, i32* %5, align 4
|
store i32 %itf.typecode, i32* %5, align 4
|
||||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef) #8
|
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef) #0
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #6
|
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #7 {
|
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i8**
|
%1 = bitcast i8* %0 to i8**
|
||||||
%2 = load i8*, i8** %1, align 4
|
%2 = load i8*, i8** %1, align 4
|
||||||
@@ -197,16 +197,14 @@ entry:
|
|||||||
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
||||||
%10 = bitcast i8* %9 to i32*
|
%10 = bitcast i8* %9 to i32*
|
||||||
%11 = load i32, i32* %10, align 4
|
%11 = load i32, i32* %10, align 4
|
||||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #8
|
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
|
attributes #1 = { nounwind "tinygo-gowrapper"="main.regularFunction" }
|
||||||
attributes #2 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
|
attributes #2 = { nounwind "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||||
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
attributes #3 = { nounwind "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||||
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
attributes #4 = { nounwind "tinygo-gowrapper" }
|
||||||
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
|
attributes #5 = { "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||||
attributes #6 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
attributes #6 = { nounwind "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||||
attributes #7 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
|
||||||
attributes #8 = { nounwind }
|
|
||||||
|
|||||||
+60
-62
@@ -1,11 +1,11 @@
|
|||||||
; ModuleID = 'goroutine.go'
|
; ModuleID = 'goroutine.go'
|
||||||
source_filename = "goroutine.go"
|
source_filename = "goroutine.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state", i8* }
|
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||||
%"internal/task.gcData" = type { i8* }
|
%"internal/task.gcData" = type { i8* }
|
||||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||||
%"internal/task.stackState" = type { i32, i32 }
|
%"internal/task.stackState" = type { i32, i32 }
|
||||||
@@ -13,84 +13,84 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
|
|
||||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @main.regularFunction(i32, i8*) #0
|
declare void @main.regularFunction(i32, i8*)
|
||||||
|
|
||||||
declare void @runtime.deadlock(i8*) #0
|
declare void @runtime.deadlock(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #2 {
|
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.int = ptrtoint i8* %0 to i32
|
%unpack.int = ptrtoint i8* %0 to i32
|
||||||
call void @main.regularFunction(i32 %unpack.int, i8* undef) #8
|
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
|
||||||
call void @runtime.deadlock(i8* undef) #8
|
call void @runtime.deadlock(i8* undef) #0
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"internal/task.start"(i32, i8*, i32, i8*) #0
|
declare void @"internal/task.start"(i32, i8*, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #3 {
|
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.int = ptrtoint i8* %0 to i32
|
%unpack.int = ptrtoint i8* %0 to i32
|
||||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
||||||
call void @runtime.deadlock(i8* undef) #8
|
call void @runtime.deadlock(i8* undef) #0
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #8
|
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%0 = bitcast i8* %n to i32*
|
%0 = bitcast i8* %n to i32*
|
||||||
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #8
|
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
|
||||||
store i32 3, i32* %0, align 4
|
store i32 3, i32* %0, align 4
|
||||||
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #8
|
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* bitcast (void (i32, i8*)* @"main.closureFunctionGoroutine$1" to i8*), i8* undef) #8
|
call void @runtime.trackPointer(i8* bitcast (void (i32, i8*)* @"main.closureFunctionGoroutine$1" to i8*), i8* undef) #0
|
||||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #8
|
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #8
|
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #0
|
||||||
%2 = bitcast i8* %1 to i32*
|
%2 = bitcast i8* %1 to i32*
|
||||||
store i32 5, i32* %2, align 4
|
store i32 5, i32* %2, align 4
|
||||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||||
%4 = bitcast i8* %3 to i8**
|
%4 = bitcast i8* %3 to i8**
|
||||||
store i8* %n, i8** %4, align 4
|
store i8* %n, i8** %4, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 16384, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 16384, i8* undef) #0
|
||||||
%5 = load i32, i32* %0, align 4
|
%5 = load i32, i32* %0, align 4
|
||||||
call void @runtime.printint32(i32 %5, i8* undef) #8
|
call void @runtime.printint32(i32 %5, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.ptr = bitcast i8* %context to i32*
|
%unpack.ptr = bitcast i8* %context to i32*
|
||||||
store i32 7, i32* %unpack.ptr, align 4
|
store i32 7, i32* %unpack.ptr, align 4
|
||||||
@@ -98,7 +98,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #4 {
|
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #3 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
%2 = load i32, i32* %1, align 4
|
%2 = load i32, i32* %1, align 4
|
||||||
@@ -106,17 +106,17 @@ entry:
|
|||||||
%4 = bitcast i8* %3 to i8**
|
%4 = bitcast i8* %3 to i8**
|
||||||
%5 = load i8*, i8** %4, align 4
|
%5 = load i8*, i8** %4, align 4
|
||||||
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
|
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
|
||||||
call void @runtime.deadlock(i8* undef) #8
|
call void @runtime.deadlock(i8* undef) #0
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.printint32(i32, i8*) #0
|
declare void @runtime.printint32(i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #1 {
|
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #8
|
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #8
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
store i32 5, i32* %1, align 4
|
store i32 5, i32* %1, align 4
|
||||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||||
@@ -125,12 +125,12 @@ entry:
|
|||||||
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
||||||
%5 = bitcast i8* %4 to void ()**
|
%5 = bitcast i8* %4 to void ()**
|
||||||
store void ()* %fn.funcptr, void ()** %5, align 4
|
store void ()* %fn.funcptr, void ()** %5, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 16384, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 16384, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @main.funcGoroutine.gowrapper(i8* %0) unnamed_addr #5 {
|
define linkonce_odr void @main.funcGoroutine.gowrapper(i8* %0) unnamed_addr #4 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i32*
|
%1 = bitcast i8* %0 to i32*
|
||||||
%2 = load i32, i32* %1, align 4
|
%2 = load i32, i32* %1, align 4
|
||||||
@@ -140,40 +140,40 @@ entry:
|
|||||||
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
||||||
%7 = bitcast i8* %6 to void (i32, i8*)**
|
%7 = bitcast i8* %6 to void (i32, i8*)**
|
||||||
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
||||||
call void %8(i32 %2, i8* %5) #8
|
call void %8(i32 %2, i8* %5) #0
|
||||||
call void @runtime.deadlock(i8* undef) #8
|
call void @runtime.deadlock(i8* undef) #0
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #1 {
|
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #1 {
|
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #8
|
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*) #0
|
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #1 {
|
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #8
|
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*) #0
|
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #8
|
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #8
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
%1 = bitcast i8* %0 to i8**
|
%1 = bitcast i8* %0 to i8**
|
||||||
store i8* %itf.value, i8** %1, align 4
|
store i8* %itf.value, i8** %1, align 4
|
||||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||||
@@ -185,14 +185,14 @@ entry:
|
|||||||
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
||||||
%5 = bitcast i8* %4 to i32*
|
%5 = bitcast i8* %4 to i32*
|
||||||
store i32 %itf.typecode, i32* %5, align 4
|
store i32 %itf.typecode, i32* %5, align 4
|
||||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 16384, i8* undef) #8
|
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 16384, i8* undef) #0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #6
|
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #7 {
|
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
|
||||||
entry:
|
entry:
|
||||||
%1 = bitcast i8* %0 to i8**
|
%1 = bitcast i8* %0 to i8**
|
||||||
%2 = load i8*, i8** %1, align 4
|
%2 = load i8*, i8** %1, align 4
|
||||||
@@ -205,17 +205,15 @@ entry:
|
|||||||
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
||||||
%10 = bitcast i8* %9 to i32*
|
%10 = bitcast i8* %9 to i32*
|
||||||
%11 = load i32, i32* %10, align 4
|
%11 = load i32, i32* %10, align 4
|
||||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #8
|
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
|
||||||
call void @runtime.deadlock(i8* undef) #8
|
call void @runtime.deadlock(i8* undef) #0
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { nounwind "tinygo-gowrapper"="main.regularFunction" }
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
|
attributes #2 = { nounwind "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
attributes #3 = { nounwind "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
attributes #4 = { nounwind "tinygo-gowrapper" }
|
||||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
|
attributes #5 = { "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||||
attributes #6 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
attributes #6 = { nounwind "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||||
attributes #7 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
|
||||||
attributes #8 = { nounwind }
|
|
||||||
|
|||||||
Vendored
+45
-47
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'interface.go'
|
; ModuleID = 'interface.go'
|
||||||
source_filename = "interface.go"
|
source_filename = "interface.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||||
@@ -22,113 +22,111 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
|
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
|
||||||
@"reflect/types.typeid:basic:int" = external constant i8
|
@"reflect/types.typeid:basic:int" = external constant i8
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._interface @main.simpleType(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._interface @main.simpleType(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* null, i8* undef) #6
|
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
|
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._interface @main.pointerType(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._interface @main.pointerType(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* null, i8* undef) #6
|
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
|
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._interface @main.interfaceType(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._interface @main.interfaceType(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* null, i8* undef) #6
|
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
|
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32) #2
|
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32) #1
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* null, i8* undef) #6
|
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
|
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32) #3
|
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32) #2
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #6
|
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #0
|
||||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||||
|
|
||||||
|
typeassert.ok: ; preds = %entry
|
||||||
|
br label %typeassert.next
|
||||||
|
|
||||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||||
ret i1 %typecode
|
ret i1 %typecode
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
|
||||||
|
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||||
|
|
||||||
typeassert.ok: ; preds = %entry
|
typeassert.ok: ; preds = %entry
|
||||||
br label %typeassert.next
|
br label %typeassert.next
|
||||||
}
|
|
||||||
|
|
||||||
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #6
|
|
||||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
|
||||||
|
|
||||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
|
|
||||||
typeassert.ok: ; preds = %entry
|
|
||||||
br label %typeassert.next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #6
|
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
|
||||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||||
|
|
||||||
|
typeassert.ok: ; preds = %entry
|
||||||
|
br label %typeassert.next
|
||||||
|
|
||||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
|
|
||||||
typeassert.ok: ; preds = %entry
|
|
||||||
br label %typeassert.next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef) #6
|
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef) #0
|
||||||
ret i8 %0
|
ret i8 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*) #4
|
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*) #3
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #1 {
|
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef) #6
|
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef) #0
|
||||||
%1 = extractvalue %runtime._string %0, 0
|
%1 = extractvalue %runtime._string %0, 0
|
||||||
call void @runtime.trackPointer(i8* %1, i8* undef) #6
|
call void @runtime.trackPointer(i8* %1, i8* undef) #0
|
||||||
ret %runtime._string %0
|
ret %runtime._string %0
|
||||||
}
|
}
|
||||||
|
|
||||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*) #5
|
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*) #4
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
|
||||||
attributes #2 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
attributes #2 = { "tinygo-methods"="reflect/methods.String() string" }
|
||||||
attributes #3 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
attributes #3 = { "tinygo-invoke"="main.$methods.foo(int) byte" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) byte" }
|
||||||
attributes #4 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
attributes #4 = { "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||||
attributes #5 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
|
||||||
attributes #6 = { nounwind }
|
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
; ModuleID = 'intrinsics.go'
|
||||||
|
source_filename = "intrinsics.go"
|
||||||
|
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||||
|
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||||
|
|
||||||
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call double @math.Sqrt(double %x, i8* undef) #0
|
||||||
|
ret double %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare double @math.Sqrt(double, i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call double @math.Trunc(double %x, i8* undef) #0
|
||||||
|
ret double %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare double @math.Trunc(double, i8*)
|
||||||
|
|
||||||
|
attributes #0 = { nounwind }
|
||||||
Vendored
+37
@@ -0,0 +1,37 @@
|
|||||||
|
; ModuleID = 'intrinsics.go'
|
||||||
|
source_filename = "intrinsics.go"
|
||||||
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call double @llvm.sqrt.f64(double %x)
|
||||||
|
ret double %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare double @llvm.sqrt.f64(double) #1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call double @llvm.trunc.f64(double %x)
|
||||||
|
ret double %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare double @llvm.trunc.f64(double) #1
|
||||||
|
|
||||||
|
attributes #0 = { nounwind }
|
||||||
|
attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Test how intrinsics are lowered: either as regular calls to the math
|
||||||
|
// functions or as LLVM builtins (such as llvm.sqrt.f64).
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
func mySqrt(x float64) float64 {
|
||||||
|
return math.Sqrt(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func myTrunc(x float64) float64 {
|
||||||
|
return math.Trunc(x)
|
||||||
|
}
|
||||||
Vendored
+24
-26
@@ -1,80 +1,78 @@
|
|||||||
; ModuleID = 'pointer.go'
|
; ModuleID = 'pointer.go'
|
||||||
source_filename = "pointer.go"
|
source_filename = "pointer.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context) unnamed_addr #1 {
|
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret [0 x i32] zeroinitializer
|
ret [0 x i32] zeroinitializer
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context) unnamed_addr #1 {
|
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = bitcast i8* %x to i32*
|
%0 = bitcast i8* %x to i32*
|
||||||
call void @runtime.trackPointer(i8* %x, i8* undef) #2
|
call void @runtime.trackPointer(i8* %x, i8* undef) #0
|
||||||
ret i32* %0
|
ret i32* %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context) unnamed_addr #1 {
|
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = bitcast i32* %x to i8*
|
%0 = bitcast i32* %x to i8*
|
||||||
call void @runtime.trackPointer(i8* %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||||
ret i8* %0
|
ret i8* %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context) unnamed_addr #1 {
|
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* %x, i8* undef) #2
|
call void @runtime.trackPointer(i8* %x, i8* undef) #0
|
||||||
ret i8* %x
|
ret i8* %x
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context) unnamed_addr #1 {
|
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #2
|
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||||
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
|
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||||
ret i8* %0
|
ret i8* %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context) unnamed_addr #1 {
|
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #2
|
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||||
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
|
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
|
||||||
call void @runtime.trackPointer(i8* %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||||
ret i8* %0
|
ret i8* %0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context) unnamed_addr #1 {
|
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = bitcast i32* %ptr to i8*
|
%0 = bitcast i32* %ptr to i8*
|
||||||
call void @runtime.trackPointer(i8* %0, i8* undef) #2
|
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||||
%1 = getelementptr i32, i32* %ptr, i32 %offset
|
%1 = getelementptr i32, i32* %ptr, i32 %offset
|
||||||
%2 = bitcast i32* %1 to i8*
|
%2 = bitcast i32* %1 to i8*
|
||||||
call void @runtime.trackPointer(i8* %2, i8* undef) #2
|
call void @runtime.trackPointer(i8* %2, i8* undef) #0
|
||||||
%3 = bitcast i32* %1 to i8*
|
%3 = bitcast i32* %1 to i8*
|
||||||
call void @runtime.trackPointer(i8* %3, i8* undef) #2
|
call void @runtime.trackPointer(i8* %3, i8* undef) #0
|
||||||
ret i32* %1
|
ret i32* %1
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
Vendored
-10
@@ -3,53 +3,44 @@ package main
|
|||||||
import _ "unsafe"
|
import _ "unsafe"
|
||||||
|
|
||||||
// Creates an external global with name extern_global.
|
// Creates an external global with name extern_global.
|
||||||
//
|
|
||||||
//go:extern extern_global
|
//go:extern extern_global
|
||||||
var externGlobal [0]byte
|
var externGlobal [0]byte
|
||||||
|
|
||||||
// Creates a
|
// Creates a
|
||||||
//
|
|
||||||
//go:align 32
|
//go:align 32
|
||||||
var alignedGlobal [4]uint32
|
var alignedGlobal [4]uint32
|
||||||
|
|
||||||
// Test conflicting pragmas (the last one counts).
|
// Test conflicting pragmas (the last one counts).
|
||||||
//
|
|
||||||
//go:align 64
|
//go:align 64
|
||||||
//go:align 16
|
//go:align 16
|
||||||
var alignedGlobal16 [4]uint32
|
var alignedGlobal16 [4]uint32
|
||||||
|
|
||||||
// Test exported functions.
|
// Test exported functions.
|
||||||
//
|
|
||||||
//export extern_func
|
//export extern_func
|
||||||
func externFunc() {
|
func externFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a function in a different package using go:linkname.
|
// Define a function in a different package using go:linkname.
|
||||||
//
|
|
||||||
//go:linkname withLinkageName1 somepkg.someFunction1
|
//go:linkname withLinkageName1 somepkg.someFunction1
|
||||||
func withLinkageName1() {
|
func withLinkageName1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import a function from a different package using go:linkname.
|
// Import a function from a different package using go:linkname.
|
||||||
//
|
|
||||||
//go:linkname withLinkageName2 somepkg.someFunction2
|
//go:linkname withLinkageName2 somepkg.someFunction2
|
||||||
func withLinkageName2()
|
func withLinkageName2()
|
||||||
|
|
||||||
// Function has an 'inline hint', similar to the inline keyword in C.
|
// Function has an 'inline hint', similar to the inline keyword in C.
|
||||||
//
|
|
||||||
//go:inline
|
//go:inline
|
||||||
func inlineFunc() {
|
func inlineFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function should never be inlined, equivalent to GCC
|
// Function should never be inlined, equivalent to GCC
|
||||||
// __attribute__((noinline)).
|
// __attribute__((noinline)).
|
||||||
//
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func noinlineFunc() {
|
func noinlineFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function should have the specified section.
|
// This function should have the specified section.
|
||||||
//
|
|
||||||
//go:section .special_function_section
|
//go:section .special_function_section
|
||||||
func functionInSection() {
|
func functionInSection() {
|
||||||
}
|
}
|
||||||
@@ -60,7 +51,6 @@ func exportedFunctionInSection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function should not: it's only a declaration and not a definition.
|
// This function should not: it's only a declaration and not a definition.
|
||||||
//
|
|
||||||
//go:section .special_function_section
|
//go:section .special_function_section
|
||||||
func undefinedFunctionNotInSection()
|
func undefinedFunctionNotInSection()
|
||||||
|
|
||||||
|
|||||||
Vendored
+17
-18
@@ -1,6 +1,6 @@
|
|||||||
; ModuleID = 'pragma.go'
|
; ModuleID = 'pragma.go'
|
||||||
source_filename = "pragma.go"
|
source_filename = "pragma.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
@extern_global = external global [0 x i8], align 1
|
@extern_global = external global [0 x i8], align 1
|
||||||
@@ -10,59 +10,58 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@undefinedGlobalNotInSection = external global i32, align 4
|
@undefinedGlobalNotInSection = external global i32, align 4
|
||||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define void @extern_func() #2 {
|
define void @extern_func() #1 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @somepkg.someFunction1(i8* %context) unnamed_addr #1 {
|
define hidden void @somepkg.someFunction1(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @somepkg.someFunction2(i8*) #0
|
declare void @somepkg.someFunction2(i8*)
|
||||||
|
|
||||||
; Function Attrs: inlinehint nounwind
|
; Function Attrs: inlinehint nounwind
|
||||||
define hidden void @main.inlineFunc(i8* %context) unnamed_addr #3 {
|
define hidden void @main.inlineFunc(i8* %context) unnamed_addr #2 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: noinline nounwind
|
; Function Attrs: noinline nounwind
|
||||||
define hidden void @main.noinlineFunc(i8* %context) unnamed_addr #4 {
|
define hidden void @main.noinlineFunc(i8* %context) unnamed_addr #3 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.functionInSection(i8* %context) unnamed_addr #1 section ".special_function_section" {
|
define hidden void @main.functionInSection(i8* %context) unnamed_addr #0 section ".special_function_section" {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define void @exportedFunctionInSection() #5 section ".special_function_section" {
|
define void @exportedFunctionInSection() #4 section ".special_function_section" {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @main.undefinedFunctionNotInSection(i8*) #0
|
declare void @main.undefinedFunctionNotInSection(i8*)
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { nounwind "wasm-export-name"="extern_func" }
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
attributes #2 = { inlinehint nounwind }
|
||||||
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #3 = { noinline nounwind }
|
||||||
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #4 = { nounwind "wasm-export-name"="exportedFunctionInSection" }
|
||||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
|
||||||
|
|||||||
Vendored
-35
@@ -1,7 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func sliceLen(ints []int) int {
|
func sliceLen(ints []int) int {
|
||||||
return len(ints)
|
return len(ints)
|
||||||
}
|
}
|
||||||
@@ -43,36 +41,3 @@ func makeArraySlice(len int) [][3]byte {
|
|||||||
func makeInt32Slice(len int) []int32 {
|
func makeInt32Slice(len int) []int32 {
|
||||||
return make([]int32, len)
|
return make([]int32, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Add32(p unsafe.Pointer, len int) unsafe.Pointer {
|
|
||||||
return unsafe.Add(p, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Add64(p unsafe.Pointer, len int64) unsafe.Pointer {
|
|
||||||
return unsafe.Add(p, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceToArray(s []int) *[4]int {
|
|
||||||
return (*[4]int)(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceToArrayConst() *[4]int {
|
|
||||||
s := make([]int, 6)
|
|
||||||
return (*[4]int)(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceInt(ptr *int, len int) []int {
|
|
||||||
return unsafe.Slice(ptr, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceUint16(ptr *byte, len uint16) []byte {
|
|
||||||
return unsafe.Slice(ptr, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceUint64(ptr *int, len uint64) []int {
|
|
||||||
return unsafe.Slice(ptr, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceInt64(ptr *int, len int64) []int {
|
|
||||||
return unsafe.Slice(ptr, len)
|
|
||||||
}
|
|
||||||
|
|||||||
Vendored
+54
-199
@@ -1,53 +1,53 @@
|
|||||||
; ModuleID = 'slice.go'
|
; ModuleID = 'slice.go'
|
||||||
source_filename = "slice.go"
|
source_filename = "slice.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret i32 %ints.len
|
ret i32 %ints.len
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret i32 %ints.cap
|
ret i32 %ints.cap
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%.not = icmp ult i32 %index, %ints.len
|
%.not = icmp ult i32 %index, %ints.len
|
||||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||||
|
|
||||||
|
lookup.throw: ; preds = %entry
|
||||||
|
call void @runtime.lookupPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
lookup.next: ; preds = %entry
|
lookup.next: ; preds = %entry
|
||||||
%0 = getelementptr inbounds i32, i32* %ints.data, i32 %index
|
%0 = getelementptr inbounds i32, i32* %ints.data, i32 %index
|
||||||
%1 = load i32, i32* %0, align 4
|
%1 = load i32, i32* %0, align 4
|
||||||
ret i32 %1
|
ret i32 %1
|
||||||
|
|
||||||
lookup.throw: ; preds = %entry
|
|
||||||
call void @runtime.lookupPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.lookupPanic(i8*) #0
|
declare void @runtime.lookupPanic(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #1 {
|
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
call void @runtime.trackPointer(i8* nonnull %varargs, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %varargs, i8* undef) #0
|
||||||
%0 = bitcast i8* %varargs to i32*
|
%0 = bitcast i8* %varargs to i32*
|
||||||
store i32 1, i32* %0, align 4
|
store i32 1, i32* %0, align 4
|
||||||
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
|
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
|
||||||
@@ -57,7 +57,7 @@ entry:
|
|||||||
%4 = bitcast i8* %3 to i32*
|
%4 = bitcast i8* %3 to i32*
|
||||||
store i32 3, i32* %4, align 4
|
store i32 3, i32* %4, align 4
|
||||||
%append.srcPtr = bitcast i32* %ints.data to i8*
|
%append.srcPtr = bitcast i32* %ints.data to i8*
|
||||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef) #2
|
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef) #0
|
||||||
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
||||||
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
||||||
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
||||||
@@ -65,18 +65,18 @@ entry:
|
|||||||
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
||||||
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
|
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
|
||||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
|
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
|
||||||
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #2
|
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
|
||||||
ret { i32*, i32, i32 } %7
|
ret { i32*, i32, i32 } %7
|
||||||
}
|
}
|
||||||
|
|
||||||
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*) #0
|
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context) unnamed_addr #1 {
|
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%append.srcPtr = bitcast i32* %ints.data to i8*
|
%append.srcPtr = bitcast i32* %ints.data to i8*
|
||||||
%append.srcPtr1 = bitcast i32* %added.data to i8*
|
%append.srcPtr1 = bitcast i32* %added.data to i8*
|
||||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef) #2
|
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef) #0
|
||||||
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
||||||
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
||||||
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
||||||
@@ -84,248 +84,103 @@ entry:
|
|||||||
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
||||||
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
|
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
|
||||||
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
|
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
|
||||||
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #2
|
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
|
||||||
ret { i32*, i32, i32 } %2
|
ret { i32*, i32, i32 } %2
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%copy.dstPtr = bitcast i32* %dst.data to i8*
|
%copy.dstPtr = bitcast i32* %dst.data to i8*
|
||||||
%copy.srcPtr = bitcast i32* %src.data to i8*
|
%copy.srcPtr = bitcast i32* %src.data to i8*
|
||||||
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef) #2
|
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef) #0
|
||||||
ret i32 %copy.n
|
ret i32 %copy.n
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*) #0
|
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context) unnamed_addr #1 {
|
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%slice.maxcap = icmp slt i32 %len, 0
|
%slice.maxcap = icmp slt i32 %len, 0
|
||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
|
slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.slicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0
|
%0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0
|
||||||
%1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1
|
||||||
%2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
|
%2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||||
ret { i8*, i32, i32 } %2
|
ret { i8*, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.slicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.slicePanic(i8*) #0
|
declare void @runtime.slicePanic(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context) unnamed_addr #1 {
|
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%slice.maxcap = icmp slt i32 %len, 0
|
%slice.maxcap = icmp slt i32 %len, 0
|
||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
|
slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.slicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.cap = shl i32 %len, 1
|
%makeslice.cap = shl i32 %len, 1
|
||||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%makeslice.array = bitcast i8* %makeslice.buf to i16*
|
%makeslice.array = bitcast i8* %makeslice.buf to i16*
|
||||||
%0 = insertvalue { i16*, i32, i32 } undef, i16* %makeslice.array, 0
|
%0 = insertvalue { i16*, i32, i32 } undef, i16* %makeslice.array, 0
|
||||||
%1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1
|
||||||
%2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
|
%2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||||
ret { i16*, i32, i32 } %2
|
ret { i16*, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.slicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context) unnamed_addr #1 {
|
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
|
slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.slicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.cap = mul i32 %len, 3
|
%makeslice.cap = mul i32 %len, 3
|
||||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%makeslice.array = bitcast i8* %makeslice.buf to [3 x i8]*
|
%makeslice.array = bitcast i8* %makeslice.buf to [3 x i8]*
|
||||||
%0 = insertvalue { [3 x i8]*, i32, i32 } undef, [3 x i8]* %makeslice.array, 0
|
%0 = insertvalue { [3 x i8]*, i32, i32 } undef, [3 x i8]* %makeslice.array, 0
|
||||||
%1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1
|
||||||
%2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
|
%2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||||
ret { [3 x i8]*, i32, i32 } %2
|
ret { [3 x i8]*, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.slicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context) unnamed_addr #1 {
|
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
||||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||||
|
|
||||||
|
slice.throw: ; preds = %entry
|
||||||
|
call void @runtime.slicePanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
slice.next: ; preds = %entry
|
slice.next: ; preds = %entry
|
||||||
%makeslice.cap = shl i32 %len, 2
|
%makeslice.cap = shl i32 %len, 2
|
||||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||||
%makeslice.array = bitcast i8* %makeslice.buf to i32*
|
%makeslice.array = bitcast i8* %makeslice.buf to i32*
|
||||||
%0 = insertvalue { i32*, i32, i32 } undef, i32* %makeslice.array, 0
|
%0 = insertvalue { i32*, i32, i32 } undef, i32* %makeslice.array, 0
|
||||||
%1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1
|
%1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1
|
||||||
%2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
|
%2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #2
|
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||||
ret { i32*, i32, i32 } %2
|
ret { i32*, i32, i32 } %2
|
||||||
|
|
||||||
slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.slicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
attributes #0 = { nounwind }
|
||||||
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = getelementptr i8, i8* %p, i32 %len
|
|
||||||
call void @runtime.trackPointer(i8* %0, i8* undef) #2
|
|
||||||
ret i8* %0
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = trunc i64 %len to i32
|
|
||||||
%1 = getelementptr i8, i8* %p, i32 %0
|
|
||||||
call void @runtime.trackPointer(i8* %1, i8* undef) #2
|
|
||||||
ret i8* %1
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = icmp ult i32 %s.len, 4
|
|
||||||
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
|
||||||
|
|
||||||
slicetoarray.next: ; preds = %entry
|
|
||||||
%1 = bitcast i32* %s.data to [4 x i32]*
|
|
||||||
ret [4 x i32]* %1
|
|
||||||
|
|
||||||
slicetoarray.throw: ; preds = %entry
|
|
||||||
call void @runtime.sliceToArrayPointerPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @runtime.sliceToArrayPointerPanic(i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
|
|
||||||
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #2
|
|
||||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
|
||||||
|
|
||||||
slicetoarray.next: ; preds = %entry
|
|
||||||
%0 = bitcast i8* %makeslice to [4 x i32]*
|
|
||||||
ret [4 x i32]* %0
|
|
||||||
|
|
||||||
slicetoarray.throw: ; preds = %entry
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = icmp ugt i32 %len, 1073741823
|
|
||||||
%1 = icmp eq i32* %ptr, null
|
|
||||||
%2 = icmp ne i32 %len, 0
|
|
||||||
%3 = and i1 %1, %2
|
|
||||||
%4 = or i1 %3, %0
|
|
||||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
|
||||||
|
|
||||||
unsafe.Slice.next: ; preds = %entry
|
|
||||||
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
|
||||||
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
|
|
||||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
|
|
||||||
%8 = bitcast i32* %ptr to i8*
|
|
||||||
call void @runtime.trackPointer(i8* %8, i8* undef) #2
|
|
||||||
ret { i32*, i32, i32 } %7
|
|
||||||
|
|
||||||
unsafe.Slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.unsafeSlicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @runtime.unsafeSlicePanic(i8*) #0
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = icmp eq i8* %ptr, null
|
|
||||||
%1 = icmp ne i16 %len, 0
|
|
||||||
%2 = and i1 %0, %1
|
|
||||||
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
|
||||||
|
|
||||||
unsafe.Slice.next: ; preds = %entry
|
|
||||||
%3 = zext i16 %len to i32
|
|
||||||
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
|
|
||||||
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
|
|
||||||
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
|
|
||||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #2
|
|
||||||
ret { i8*, i32, i32 } %6
|
|
||||||
|
|
||||||
unsafe.Slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.unsafeSlicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = icmp ugt i64 %len, 1073741823
|
|
||||||
%1 = icmp eq i32* %ptr, null
|
|
||||||
%2 = icmp ne i64 %len, 0
|
|
||||||
%3 = and i1 %1, %2
|
|
||||||
%4 = or i1 %3, %0
|
|
||||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
|
||||||
|
|
||||||
unsafe.Slice.next: ; preds = %entry
|
|
||||||
%5 = trunc i64 %len to i32
|
|
||||||
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
|
||||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
|
||||||
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
|
||||||
%9 = bitcast i32* %ptr to i8*
|
|
||||||
call void @runtime.trackPointer(i8* %9, i8* undef) #2
|
|
||||||
ret { i32*, i32, i32 } %8
|
|
||||||
|
|
||||||
unsafe.Slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.unsafeSlicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
|
||||||
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
|
|
||||||
entry:
|
|
||||||
%0 = icmp ugt i64 %len, 1073741823
|
|
||||||
%1 = icmp eq i32* %ptr, null
|
|
||||||
%2 = icmp ne i64 %len, 0
|
|
||||||
%3 = and i1 %1, %2
|
|
||||||
%4 = or i1 %3, %0
|
|
||||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
|
||||||
|
|
||||||
unsafe.Slice.next: ; preds = %entry
|
|
||||||
%5 = trunc i64 %len to i32
|
|
||||||
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
|
||||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
|
||||||
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
|
||||||
%9 = bitcast i32* %ptr to i8*
|
|
||||||
call void @runtime.trackPointer(i8* %9, i8* undef) #2
|
|
||||||
ret { i32*, i32, i32 } %8
|
|
||||||
|
|
||||||
unsafe.Slice.throw: ; preds = %entry
|
|
||||||
call void @runtime.unsafeSlicePanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
Vendored
+27
-29
@@ -1,101 +1,99 @@
|
|||||||
; ModuleID = 'string.go'
|
; ModuleID = 'string.go'
|
||||||
source_filename = "string.go"
|
source_filename = "string.go"
|
||||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%runtime._string = type { i8*, i32 }
|
%runtime._string = type { i8*, i32 }
|
||||||
|
|
||||||
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
|
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._string @main.someString(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._string @main.someString(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$string", i32 0, i32 0), i32 3 }
|
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$string", i32 0, i32 0), i32 3 }
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden %runtime._string @main.zeroLengthString(i8* %context) unnamed_addr #1 {
|
define hidden %runtime._string @main.zeroLengthString(i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret %runtime._string zeroinitializer
|
ret %runtime._string zeroinitializer
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context) unnamed_addr #1 {
|
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
ret i32 %s.len
|
ret i32 %s.len
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context) unnamed_addr #1 {
|
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%.not = icmp ult i32 %index, %s.len
|
%.not = icmp ult i32 %index, %s.len
|
||||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||||
|
|
||||||
|
lookup.throw: ; preds = %entry
|
||||||
|
call void @runtime.lookupPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
lookup.next: ; preds = %entry
|
lookup.next: ; preds = %entry
|
||||||
%0 = getelementptr inbounds i8, i8* %s.data, i32 %index
|
%0 = getelementptr inbounds i8, i8* %s.data, i32 %index
|
||||||
%1 = load i8, i8* %0, align 1
|
%1 = load i8, i8* %0, align 1
|
||||||
ret i8 %1
|
ret i8 %1
|
||||||
|
|
||||||
lookup.throw: ; preds = %entry
|
|
||||||
call void @runtime.lookupPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @runtime.lookupPanic(i8*) #0
|
declare void @runtime.lookupPanic(i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #2
|
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*) #0
|
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #2
|
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
|
||||||
%1 = xor i1 %0, true
|
%1 = xor i1 %0, true
|
||||||
ret i1 %1
|
ret i1 %1
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #1 {
|
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef) #2
|
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef) #0
|
||||||
ret i1 %0
|
ret i1 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*) #0
|
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*)
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context) unnamed_addr #1 {
|
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context) unnamed_addr #0 {
|
||||||
entry:
|
entry:
|
||||||
%0 = zext i8 %x to i32
|
%0 = zext i8 %x to i32
|
||||||
%.not = icmp ult i32 %0, %s.len
|
%.not = icmp ult i32 %0, %s.len
|
||||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||||
|
|
||||||
|
lookup.throw: ; preds = %entry
|
||||||
|
call void @runtime.lookupPanic(i8* undef) #0
|
||||||
|
unreachable
|
||||||
|
|
||||||
lookup.next: ; preds = %entry
|
lookup.next: ; preds = %entry
|
||||||
%1 = getelementptr inbounds i8, i8* %s.data, i32 %0
|
%1 = getelementptr inbounds i8, i8* %s.data, i32 %0
|
||||||
%2 = load i8, i8* %1, align 1
|
%2 = load i8, i8* %1, align 1
|
||||||
ret i8 %2
|
ret i8 %2
|
||||||
|
|
||||||
lookup.throw: ; preds = %entry
|
|
||||||
call void @runtime.lookupPanic(i8* undef) #2
|
|
||||||
unreachable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { nounwind }
|
||||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
|
||||||
attributes #2 = { nounwind }
|
|
||||||
|
|||||||
+14
-11
@@ -3,25 +3,28 @@ package compiler
|
|||||||
// This file implements volatile loads/stores in runtime/volatile.LoadT and
|
// This file implements volatile loads/stores in runtime/volatile.LoadT and
|
||||||
// runtime/volatile.StoreT as compiler builtins.
|
// runtime/volatile.StoreT as compiler builtins.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
"tinygo.org/x/go-llvm"
|
||||||
|
)
|
||||||
|
|
||||||
// createVolatileLoad is the implementation of the intrinsic function
|
// createVolatileLoad is the implementation of the intrinsic function
|
||||||
// runtime/volatile.LoadT().
|
// runtime/volatile.LoadT().
|
||||||
func (b *builder) createVolatileLoad() {
|
func (b *builder) createVolatileLoad(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||||
b.createFunctionStart(true)
|
addr := b.getValue(instr.Args[0])
|
||||||
addr := b.getValue(b.fn.Params[0])
|
b.createNilCheck(instr.Args[0], addr, "deref")
|
||||||
b.createNilCheck(b.fn.Params[0], addr, "deref")
|
|
||||||
val := b.CreateLoad(addr, "")
|
val := b.CreateLoad(addr, "")
|
||||||
val.SetVolatile(true)
|
val.SetVolatile(true)
|
||||||
b.CreateRet(val)
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createVolatileStore is the implementation of the intrinsic function
|
// createVolatileStore is the implementation of the intrinsic function
|
||||||
// runtime/volatile.StoreT().
|
// runtime/volatile.StoreT().
|
||||||
func (b *builder) createVolatileStore() {
|
func (b *builder) createVolatileStore(instr *ssa.CallCommon) (llvm.Value, error) {
|
||||||
b.createFunctionStart(true)
|
addr := b.getValue(instr.Args[0])
|
||||||
addr := b.getValue(b.fn.Params[0])
|
val := b.getValue(instr.Args[1])
|
||||||
val := b.getValue(b.fn.Params[1])
|
b.createNilCheck(instr.Args[0], addr, "deref")
|
||||||
b.createNilCheck(b.fn.Params[0], addr, "deref")
|
|
||||||
store := b.CreateStore(val, addr)
|
store := b.CreateStore(val, addr)
|
||||||
store.SetVolatile(true)
|
store.SetVolatile(true)
|
||||||
b.CreateRetVoid()
|
return llvm.Value{}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -8,7 +8,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"golang.org/x/tools/go/buildutil"
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,11 +111,9 @@ func TestCorpus(t *testing.T) {
|
|||||||
|
|
||||||
opts := optionsFromTarget(target, sema)
|
opts := optionsFromTarget(target, sema)
|
||||||
opts.Directory = dir
|
opts.Directory = dir
|
||||||
var tags buildutil.TagsFlag
|
opts.Tags = repo.Tags
|
||||||
tags.Set(repo.Tags)
|
|
||||||
opts.Tags = []string(tags)
|
|
||||||
|
|
||||||
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", false, "")
|
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test error: %v", err)
|
t.Errorf("test error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,19 @@
|
|||||||
module github.com/tinygo-org/tinygo
|
module github.com/tinygo-org/tinygo
|
||||||
|
|
||||||
go 1.18
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc
|
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a
|
||||||
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/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/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.8
|
||||||
github.com/mattn/go-tty v0.0.4
|
go.bug.st/serial v1.1.3
|
||||||
go.bug.st/serial v1.3.5
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
|
||||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
|
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
|
||||||
golang.org/x/tools v0.1.11
|
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7
|
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
|
||||||
github.com/creack/goselect v0.1.2 // indirect
|
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
|
||||||
github.com/gobwas/ws v1.1.0 // indirect
|
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user