Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem 73dc9963ed reflect: move binary flag into map type
The map type had a byte of padding ready for such a flag (on all systems
except AVR). I want to use the now-free flag bit in the meta byte in a
followup PR, this just lays the groundwork.
2024-07-28 14:42:14 +02:00
345 changed files with 3308 additions and 10430 deletions
+3 -7
View File
@@ -90,8 +90,6 @@ commands:
name: Check Go code formatting name: Check Go code formatting
command: make fmt-check lint command: make fmt-check lint
- run: make gen-device -j4 - run: make gen-device -j4
# TODO: change this to -skip='TestErrors|TestWasm' with Go 1.20
- run: go test -tags=llvm<<parameters.llvm>> -short -run='TestBuild|TestTest|TestGetList|TestTraceback'
- run: make smoketest XTENSA=0 - run: make smoketest XTENSA=0
- save_cache: - save_cache:
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }} key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
@@ -106,12 +104,10 @@ jobs:
steps: steps:
- test-linux: - test-linux:
llvm: "15" llvm: "15"
# "make lint" fails before go 1.21 because internal/tools/go.mod specifies packages that require go 1.21
fmt-check: false
resource_class: large resource_class: large
test-llvm18-go123: test-llvm18-go122:
docker: docker:
- image: golang:1.23-bullseye - image: golang:1.22-bullseye
steps: steps:
- test-linux: - test-linux:
llvm: "18" llvm: "18"
@@ -124,4 +120,4 @@ workflows:
# least the smoke tests still pass. # least the smoke tests still pass.
- test-llvm15-go119 - test-llvm15-go119
# This tests LLVM 18 support when linking against system libraries. # This tests LLVM 18 support when linking against system libraries.
- test-llvm18-go123 - test-llvm18-go122
-3
View File
@@ -1,3 +0,0 @@
# These are supported funding model platforms
open_collective: tinygo
+13 -15
View File
@@ -16,32 +16,28 @@ jobs:
name: build-macos name: build-macos
strategy: strategy:
matrix: matrix:
# macos-13: amd64 (oldest supported version as of 18-10-2024) # macos-12: amd64 (oldest supported version as of 05-02-2024)
# macos-14: arm64 (oldest arm64 version) # macos-14: arm64 (oldest arm64 version)
os: [macos-13, macos-14] os: [macos-12, macos-14]
include: include:
- os: macos-13 - os: macos-12
goarch: amd64 goarch: amd64
- os: macos-14 - os: macos-14
goarch: arm64 goarch: arm64
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: exit early
run: command-does-not-exist
- name: Install Dependencies - name: Install Dependencies
shell: bash
run: | run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
@@ -76,6 +72,7 @@ jobs:
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'
shell: bash
run: | run: |
# fetch LLVM source # fetch LLVM source
rm -rf llvm-project rm -rf llvm-project
@@ -103,13 +100,15 @@ jobs:
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make -j3 gen-device
- name: Test TinyGo - name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short" run: make test GOTESTFLAGS="-short"
- name: Build TinyGo release tarball - name: Build TinyGo release tarball
run: make release -j3 run: make release -j3
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test run: make tinygo-test
- name: Make release artifact - name: Make release artifact
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz shell: bash
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact - name: Publish release artifact
# Note: this release artifact is double-zipped, see: # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39 # https://github.com/actions/upload-artifact/issues/39
@@ -119,9 +118,10 @@ jobs:
# We're doing the former here, to keep artifact uploads fast. # We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: darwin-${{ matrix.goarch }}-double-zipped
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Smoke tests - name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew: test-macos-homebrew:
name: homebrew-install name: homebrew-install
@@ -130,8 +130,6 @@ jobs:
matrix: matrix:
version: [16, 17, 18] version: [16, 17, 18]
steps: steps:
- name: exit early
run: command-does-not-exist
- name: Set up Homebrew - name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master uses: Homebrew/actions/setup-homebrew@master
- name: Fix Python symlinks - name: Fix Python symlinks
@@ -147,7 +145,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }} run: go install -tags=llvm${{ matrix.version }}
+18 -32
View File
@@ -18,12 +18,8 @@ jobs:
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.23-alpine image: golang:1.22-alpine
outputs:
version: ${{ steps.version.outputs.version }}
steps: steps:
- name: exit early
run: command-does-not-exist
- name: Install apk dependencies - name: Install apk dependencies
# tar: needed for actions/cache@v4 # tar: needed for actions/cache@v4
# git+openssh: needed for checkout (I think?) # git+openssh: needed for checkout (I think?)
@@ -36,9 +32,6 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Cache Go - name: Cache Go
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
@@ -122,20 +115,18 @@ jobs:
gem install --no-document fpm gem install --no-document fpm
- name: Run linter - name: Run linter
run: make lint run: make lint
- name: Run spellcheck
run: make spell
- name: Build TinyGo release - name: Build TinyGo release
run: | run: |
make release deb -j3 STATIC=1 make release deb -j3 STATIC=1
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb cp -p build/release.deb /tmp/tinygo_amd64.deb
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ steps.version.outputs.version }} name: linux-amd64-double-zipped
path: | path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz /tmp/tinygo.linux-amd64.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb /tmp/tinygo_amd64.deb
test-linux-build: test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests. # Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -148,7 +139,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -159,11 +150,11 @@ jobs:
- name: Download release artifact - name: Download release artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-amd64-double-zipped
- name: Extract release tarball - name: Extract release tarball
run: | run: |
mkdir -p ~/lib mkdir -p ~/lib
tar -C ~/lib -xf tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- run: make tinygo-test-wasip1-fast - run: make tinygo-test-wasip1-fast
- run: make tinygo-test-wasip2-fast - run: make tinygo-test-wasip2-fast
@@ -173,8 +164,6 @@ jobs:
# potential bugs. # potential bugs.
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: exit early
run: command-does-not-exist
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
@@ -193,7 +182,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@@ -306,9 +295,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Get TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install apt dependencies - name: Install apt dependencies
run: | run: |
sudo apt-get update sudo apt-get update
@@ -319,7 +305,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
@@ -393,11 +379,11 @@ jobs:
- name: Download amd64 release - name: Download amd64 release
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-amd64-double-zipped
- name: Extract amd64 release - name: Extract amd64 release
run: | run: |
mkdir -p build/release mkdir -p build/release
tar -xf tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz -C build/release tinygo tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
- name: Modify release - name: Modify release
run: | run: |
cp -p build/tinygo build/release/tinygo/bin cp -p build/tinygo build/release/tinygo/bin
@@ -405,12 +391,12 @@ jobs:
- name: Create ${{ matrix.goarch }} release - name: Create ${{ matrix.goarch }} release
run: | run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }} make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: linux-${{ matrix.goarch }}-double-zipped
path: | path: |
/tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
/tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb /tmp/tinygo_${{ matrix.libc }}.deb
-7
View File
@@ -15,13 +15,6 @@ jobs:
nix-test: nix-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: exit early
run: command-does-not-exist
- name: Uninstall system LLVM
# Hack to work around issue where we still include system headers for
# some reason.
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
run: sudo apt-get remove llvm-18
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Pull musl - name: Pull musl
+1 -1
View File
@@ -2,7 +2,7 @@
# still works after checking out the dev branch (that is, when going from LLVM # still works after checking out the dev branch (that is, when going from LLVM
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed). # 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-18 main' | sudo tee /etc/apt/sources.list.d/llvm.list echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' | sudo tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update sudo apt-get update
sudo apt-get install --no-install-recommends -y \ sudo apt-get install --no-install-recommends -y \
-4
View File
@@ -9,14 +9,10 @@ concurrency:
jobs: jobs:
sizediff: sizediff:
# Note: when updating the Ubuntu version, also update the Ubuntu version in
# sizediff-install-pkgs.sh
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions: permissions:
pull-requests: write pull-requests: write
steps: steps:
- name: exit early
run: command-does-not-exist
# Prepare, install tools # Prepare, install tools
- name: Add GOBIN to $PATH - name: Add GOBIN to $PATH
run: | run: |
@@ -1,4 +0,0 @@
#!/bin/sh
# Extract the version string from the source code, to be stored in a variable.
grep 'const version' goenv/version.go | sed 's/^const version = "\(.*\)"$/version=\1/g'
+29 -55
View File
@@ -14,8 +14,6 @@ concurrency:
jobs: jobs:
build-windows: build-windows:
runs-on: windows-2022 runs-on: windows-2022
outputs:
version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Configure pagefile - name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4 uses: al-cheb/configure-pagefile-action@v1.4
@@ -23,30 +21,22 @@ jobs:
minimum-size: 8GB minimum-size: 8GB
maximum-size: 24GB maximum-size: 24GB
disk-root: "C:" disk-root: "C:"
#- uses: brechtm/setup-scoop@v2 - uses: brechtm/setup-scoop@v2
# with: with:
# scoop_update: 'false' scoop_update: 'false'
#- name: Install Dependencies - name: Install Dependencies
# shell: bash shell: bash
# run: | run: |
# scoop install ninja binaryen scoop install ninja binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: submodules with:
shell: bash submodules: true
run: git submodule update --init lib/mingw-w64 - name: Install Go
- name: Extract TinyGo version uses: actions/setup-go@v5
id: version with:
shell: bash go-version: '1.22'
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT" cache: true
- name: command
shell: bash
run: go env
#- name: Install Go
# uses: actions/setup-go@v5
# with:
# go-version: '1.23'
# cache: true
- name: Restore cached LLVM source - name: Restore cached LLVM source
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
@@ -95,25 +85,6 @@ jobs:
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Restore Go cache
uses: actions/cache/restore@v4
with:
key: go-cache-v2
path: |
C:/Users/runneradmin/AppData/Local/go-build
C:/Users/runneradmin/go/pkg/mod
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short -run=TestBuild -v"
- name: Save Go cache
uses: actions/cache/save@v4
with:
key: go-cache-v2
path: |
C:/Users/runneradmin/AppData/Local/go-build
C:/Users/runneradmin/go/pkg/mod
- name: exit
run: command-does-not-exist
- name: Cache wasi-libc sysroot - name: Cache wasi-libc sysroot
uses: actions/cache@v4 uses: actions/cache@v4
id: cache-wasi-libc id: cache-wasi-libc
@@ -128,13 +99,16 @@ jobs:
scoop install wasmtime@14.0.4 scoop install wasmtime@14.0.4
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
- name: Build TinyGo release tarball - name: Build TinyGo release tarball
shell: bash shell: bash
run: make build/release -j4 run: make build/release -j4
- name: Make release artifact - name: Make release artifact
shell: bash shell: bash
working-directory: build/release working-directory: build/release
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo run: 7z -tzip a release.zip tinygo
- name: Publish release artifact - name: Publish release artifact
# Note: this release artifact is double-zipped, see: # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39 # https://github.com/actions/upload-artifact/issues/39
@@ -144,8 +118,8 @@ jobs:
# We're doing the former here, to keep artifact uploads fast. # We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ steps.version.outputs.version }} name: windows-amd64-double-zipped
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip path: build/release/release.zip
smoke-test-windows: smoke-test-windows:
runs-on: windows-2022 runs-on: windows-2022
@@ -169,17 +143,17 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Smoke tests - name: Smoke tests
shell: bash shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -199,17 +173,17 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -235,16 +209,16 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.22'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }} name: windows-amd64-double-zipped
path: build/ path: build/
- name: Unzip TinyGo build - name: Unzip TinyGo build
shell: bash shell: bash
working-directory: build working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r run: 7z x release.zip -r
- name: Test stdlib packages on wasip1 - name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
-2
View File
@@ -20,8 +20,6 @@ src/device/stm32/*.go
src/device/stm32/*.s src/device/stm32/*.s
src/device/kendryte/*.go src/device/kendryte/*.go
src/device/kendryte/*.s src/device/kendryte/*.s
src/device/renesas/*.go
src/device/renesas/*.s
src/device/rp/*.go src/device/rp/*.go
src/device/rp/*.s src/device/rp/*.s
./vendor ./vendor
+3
View File
@@ -32,6 +32,9 @@
[submodule "lib/macos-minimal-sdk"] [submodule "lib/macos-minimal-sdk"]
path = lib/macos-minimal-sdk path = lib/macos-minimal-sdk
url = https://github.com/aykevl/macos-minimal-sdk.git url = https://github.com/aykevl/macos-minimal-sdk.git
[submodule "lib/renesas-svd"]
path = lib/renesas-svd
url = https://github.com/tinygo-org/renesas-svd.git
[submodule "src/net"] [submodule "src/net"]
path = src/net path = src/net
url = https://github.com/tinygo-org/net.git url = https://github.com/tinygo-org/net.git
-15
View File
@@ -28,21 +28,6 @@ build tools to be built. Go is of course necessary to build TinyGo itself.
The rest of this guide assumes you're running Linux, but it should be equivalent The rest of this guide assumes you're running Linux, but it should be equivalent
on a different system like Mac. on a different system like Mac.
## Using GNU Make
The static build of TinyGo is driven by GNUmakefile, which provides a help target for quick reference:
% make help
clean Remove build directory
fmt Reformat source
fmt-check Warn if any source needs reformatting
gen-device Generate microcontroller-specific sources
llvm-source Get LLVM sources
llvm-build Build LLVM
tinygo Build the TinyGo compiler
lint Lint source tree
spell Spellcheck source tree
## Download the source ## Download the source
The first step is to download the TinyGo sources (use `--recursive` if you clone The first step is to download the TinyGo sources (use `--recursive` if you clone
+3 -113
View File
@@ -1,113 +1,3 @@
0.34.0
---
* **general**
- fix `GOOS=wasip1` for `tinygo test`
- add `-C DIR` flag
- add initial documentation for project governance
- add `-ldflags='-extldflags=...'` support
- improve usage message with `tinygo help` and when passing invalid parameters
* **compiler**
- `builder`: remove environment variables when invoking Clang, to avoid the environment changing the behavior
- `builder`: check for the Go toolchain version used to compile TinyGo
- `cgo`: add `C.CBytes` implementation
- `compiler`: fix passing weirdly-padded structs as parameters to new goroutines
- `compiler`: support pragmas on generic functions
- `compiler`: do not let the slice buffer escape when casting a `[]byte` or `[]rune` to a string, to help escape analysis
- `compiler`: conform to the latest iteration of the wasm types proposal
- `loader`: don't panic when main package is not named 'main'
- `loader`: make sure we always return type checker errors even without type errors
- `transform`: optimize range over `[]byte(string)`
* **standard library**
- `crypto/x509`: add package stub to build crypto/x509 on macOS
- `machine/usb/adc/midi`: fix `PitchBend`
- `os`: add `Truncate` stub for baremetal
- `os`: add stubs for `os.File` deadlines
- `os`: add internal `net.newUnixFile` for the net package
- `runtime`: stub runtime_{Before,After}Exec for linkage
- `runtime`: randomize map accesses
- `runtime`: support `maps.Clone`
- `runtime`: add more fields to `MemStats`
- `runtime`: implement newcoro, coroswitch to support package iter
- `runtime`: disallow defer in interrupts
- `runtime`: add support for os/signal on Linux and MacOS
- `runtime`: add gc layout info for some basic types to help the precise GC
- `runtime`: bump GC mark stack size to avoid excessive heap rescans
* **targets**
- `darwin`: use Go standard library syscall package instead of a custom one
- `fe310`: support GPIO `PinInput`
- `mips`: fix compiler crash with GOMIPS=softfloat and defer
- `mips`: add big-endian (GOARCH=mips) support
- `mips`: use MIPS32 (instead of MIPS32R2) as the instruction set for wider compatibility
- `wasi`: add relative and absolute --dir options to wasmtime args
- `wasip2`: add wasmtime -S args to support network interfaces
- `wasm`: add `//go:wasmexport` support (for all WebAssembly targets)
- `wasm`: use precise instead of conservative GC for WebAssembly (including WASI)
- `wasm-unknown`: add bulk memory flags since basically every runtime has it now
* **boards**
- add RAKwireless RAK4631
- add WaveShare ESP-C3-32S-Kit
0.33.0
---
* **general**
- use latest version of x/tools
- add chromeos 9p support for flashing
- sort compiler error messages by source position in a package
- don't include prebuilt libraries in the release to simplify packaging and reduce the release tarball size
- show runtime panic addresses for `tinygo run`
- support Go 1.23 (including all new language features)
- `test`: support GOOS/GOARCH pairs in the `-target` flag
- `test`: remove message after test binary built
* **compiler**
- remove unused registers for x86_64 linux syscalls
- remove old atomics workaround for AVR (not necessary in modern LLVM versions)
- support `golang.org/x/sys/unix` syscalls
- `builder`: remove workaround for generics race condition
- `builder`: add package ID to compiler and optimization error messages
- `builder`: show better error messages for some common linker errors
- `cgo`: support preprocessor macros passed on the command line
- `cgo`: use absolute paths for error messages
- `cgo`: add support for printf
- `loader`: handle `go list` errors inside TinyGo (for better error messages)
- `transform`: fix incorrect alignment of heap-to-stack transform
- `transform`: use thinlto-pre-link passes (instead of the full pipeline) to speed up compilation speed slightly
* **standard library**
- `crypto/tls`: add CipherSuiteName and some extra fields to ConnectionSTate
- `internal/abi`: implement initial version of this package
- `machine`: use new `internal/binary` package
- `machine`: rewrite Reply() to fix sending long replies in I2C Target Mode
- `machine/usb/descriptor`: Reset joystick physical
- `machine/usb/descriptor`: Drop second joystick hat
- `machine/usb/descriptor`: Add more HID... functions
- `machine/usb/descriptor`: Fix encoding of values
- `machine/usb/hid/joystick`: Allow more hat switches
- `os`: add `Chown`, `Truncate`
- `os/user`: use stdlib version of this package
- `reflect`: return correct name for the `unsafe.Pointer` type
- `reflect`: implement `Type.Overflow*` functions
- `runtime`: implement dummy `getAuxv` to satisfy golang.org/x/sys/
- `runtime`: don't zero out new allocations for `-gc=leaking` when they are already zeroed
- `runtime`: simplify slice growing/appending code
- `runtime`: print a message when a fatal signal like SIGSEGV happens
- `runtime/debug`: add `GoVersion` to `debug.BuildInfo`
- `sync`: add `Map.Clear()`
- `sync/atomic`: add And* and Or* compiler intrinsics needed for Go 1.23
- `syscall`: add `Fork` and `Execve`
- `syscall`: add all MacOS errno values
- `testing`: stub out `T.Deadline`
- `unique`: implement custom (naive) version of the unique package
* **targets**
- `arm`: support `GOARM=*,softfloat` (softfloat support for ARM v5, v6, and v7)
- `mips`: add linux/mipsle (and experimental linux/mips) support
- `mips`: add `GOMIPS=softfloat` support
- `wasip2`: add WASI preview 2 support
- `wasm/js`: add `node:` prefix in `require()` call of wasm_exec.js
- `wasm-unknown`: make sure the `os` package can be imported
- `wasm-unknown`: remove import-memory flag
0.32.0 0.32.0
--- ---
@@ -128,7 +18,7 @@
- `builder`: keep un-wasm-opt'd .wasm if -work was passed - `builder`: keep un-wasm-opt'd .wasm if -work was passed
- `builder`: make sure wasm-opt command line is printed if asked - `builder`: make sure wasm-opt command line is printed if asked
- `cgo`: implement shift operations in preprocessor macros - `cgo`: implement shift operations in preprocessor macros
- `interp`: checking for methodset existence - `interp`: checking for methodset existance
* **standard library** * **standard library**
- `machine`: add `__tinygo_spi_tx` function to simulator - `machine`: add `__tinygo_spi_tx` function to simulator
@@ -327,7 +217,7 @@
- `reflect`: add SetZero - `reflect`: add SetZero
- `reflect`: fix iterating over maps with interface{} keys - `reflect`: fix iterating over maps with interface{} keys
- `reflect`: implement Value.Grow - `reflect`: implement Value.Grow
- `reflect`: remove unnecessary heap allocations - `reflect`: remove unecessary heap allocations
- `reflect`: use .key() instead of a type assert - `reflect`: use .key() instead of a type assert
- `sync`: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues - `sync`: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues
* **targets** * **targets**
@@ -2006,7 +1896,7 @@
- allow packages like github.com/tinygo-org/tinygo/src/\* by aliasing it - allow packages like github.com/tinygo-org/tinygo/src/\* by aliasing it
- remove `//go:volatile` support - remove `//go:volatile` support
It has been replaced with the runtime/volatile package. It has been replaced with the runtime/volatile package.
- allow pointers in map keys - allow poiners in map keys
- support non-constant syscall numbers - support non-constant syscall numbers
- implement non-blocking selects - implement non-blocking selects
- add support for the `-tags` flag - add support for the `-tags` flag
+2 -2
View File
@@ -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.23 AS tinygo-llvm FROM golang:1.22 AS tinygo-llvm
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-15 ninja-build && \ apt-get install -y apt-utils make cmake clang-15 ninja-build && \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without # tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc). # all the build tools etc).
FROM golang:1.23 AS tinygo-compiler FROM golang:1.22 AS tinygo-compiler
# Copy tinygo build. # Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+38 -85
View File
@@ -175,23 +175,23 @@ ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
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_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif endif
clean: ## Remove build directory clean:
@rm -rf build @rm -rf build
FMT_PATHS = ./*.go builder cgo/*.go compiler interp loader src transform FMT_PATHS = ./*.go builder cgo/*.go compiler interp loader src transform
fmt: ## Reformat source fmt:
@gofmt -l -w $(FMT_PATHS) @gofmt -l -w $(FMT_PATHS)
fmt-check: ## Warn if any source needs reformatting fmt-check:
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1 @unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp gen-device-renesas ## Generate microcontroller-specific sources gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp
ifneq ($(STM32), 0) ifneq ($(STM32), 0)
gen-device: gen-device-stm32 gen-device: gen-device-stm32
endif endif
gen-device-avr: gen-device-avr:
#@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi @if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/ $(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/ ./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/ ./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
@@ -234,19 +234,21 @@ gen-device-rp: build/gen-device-svd
GO111MODULE=off $(GO) fmt ./src/device/rp GO111MODULE=off $(GO) fmt ./src/device/rp
gen-device-renesas: build/gen-device-svd gen-device-renesas: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/cmsis-svd/cmsis-svd-data/tree/master/data/Renesas lib/cmsis-svd/data/Renesas/ src/device/renesas/ ./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
GO111MODULE=off $(GO) fmt ./src/device/renesas GO111MODULE=off $(GO) fmt ./src/device/renesas
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm: $(LLVM_PROJECTDIR)/llvm:
git clone -b tinygo_xtensa_release_18.1.2 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR) git clone -b tinygo_xtensa_release_18.1.2 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources 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:
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;AVR;Mips;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_ZSTD=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;AVR;Mips;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_ZSTD=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)
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja ## Build LLVM # Build LLVM.
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS) cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS)
ifneq ($(USE_SYSTEM_BINARYEN),1) ifneq ($(USE_SYSTEM_BINARYEN),1)
@@ -263,11 +265,11 @@ endif
.PHONY: wasi-libc .PHONY: wasi-libc
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
#@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi @if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM) cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM)
# Generate WASI syscall bindings # Generate WASI syscall bindings
WASM_TOOLS_MODULE=github.com/bytecodealliance/wasm-tools-go WASM_TOOLS_MODULE=github.com/ydnar/wasm-tools-go
.PHONY: wasi-syscall .PHONY: wasi-syscall
wasi-syscall: wasi-cm wasi-syscall: wasi-cm
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
@@ -289,11 +291,12 @@ ifeq (, $(shell which node))
endif endif
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi @if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi
tinygo: ## Build the TinyGo compiler # Build the Go compiler.
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" . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
test: #wasi-libc check-nodejs-version test: wasi-libc check-nodejs-version
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -race -buildmode exe -tags "byollvm osusergo" . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi # Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \ TEST_PACKAGES_SLOW = \
@@ -303,34 +306,26 @@ TEST_PACKAGES_SLOW = \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows # Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \ TEST_PACKAGES_FAST = \
cmp \
compress/lzw \ compress/lzw \
compress/zlib \ compress/zlib \
container/heap \ container/heap \
container/list \ container/list \
container/ring \ container/ring \
crypto/des \ crypto/des \
crypto/ecdsa \
crypto/elliptic \
crypto/md5 \ crypto/md5 \
crypto/rc4 \ crypto/rc4 \
crypto/sha1 \ crypto/sha1 \
crypto/sha256 \ crypto/sha256 \
crypto/sha512 \ crypto/sha512 \
database/sql/driver \
debug/macho \ debug/macho \
embed/internal/embedtest \ embed/internal/embedtest \
encoding \ encoding \
encoding/ascii85 \ encoding/ascii85 \
encoding/asn1 \
encoding/base32 \ encoding/base32 \
encoding/base64 \ encoding/base64 \
encoding/csv \ encoding/csv \
encoding/hex \ encoding/hex \
go/ast \
go/format \
go/scanner \ go/scanner \
go/version \
hash \ hash \
hash/adler32 \ hash/adler32 \
hash/crc64 \ hash/crc64 \
@@ -352,7 +347,6 @@ TEST_PACKAGES_FAST = \
unicode \ unicode \
unicode/utf16 \ unicode/utf16 \
unicode/utf8 \ unicode/utf8 \
unique \
$(nil) $(nil)
# Assume this will go away before Go2, so only check minor version. # Assume this will go away before Go2, so only check minor version.
@@ -365,41 +359,30 @@ endif
# archive/zip requires os.ReadAt, which is not yet supported on windows # archive/zip requires os.ReadAt, which is not yet supported on windows
# bytes requires mmap # bytes requires mmap
# compress/flate appears to hang on wasi # compress/flate appears to hang on wasi
# crypto/aes fails on wasi, needs panic()/recover()
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic # 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 # debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# image requires recover(), which is not yet supported on wasi # image requires recover(), which is not yet supported on wasi
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi # io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# mime: fail on wasi; neds panic()/recover()
# mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK
# mime/quotedprintable requires syscall.Faccessat # mime/quotedprintable requires syscall.Faccessat
# net/mail: needs wasip1 syscall.FDFLAG_NONBLOCK
# net/ntextproto: needs wasip1 syscall.FDFLAG_NONBLOCK
# regexp/syntax: fails on wasip1; needs panic()/recover()
# strconv requires recover() which is not yet supported on wasi # strconv requires recover() which is not yet supported on wasi
# text/tabwriter requires recover(), which is not yet supported on wasi # text/tabwriter requries recover(), which is not yet supported on wasi
# text/template/parse 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 # testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
# Additional standard library packages that pass tests on individual platforms # Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \ TEST_PACKAGES_LINUX := \
archive/zip \ archive/zip \
bytes \
compress/flate \ compress/flate \
crypto/aes \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
image \ image \
io/ioutil \ io/ioutil \
mime \
mime/multipart \
mime/quotedprintable \ mime/quotedprintable \
net \ net \
net/mail \
net/textproto \
os/user \
regexp/syntax \
strconv \ strconv \
testing/fstest \
text/tabwriter \ text/tabwriter \
text/template/parse text/template/parse
@@ -408,7 +391,6 @@ TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
TEST_PACKAGES_WINDOWS := \ TEST_PACKAGES_WINDOWS := \
compress/flate \ compress/flate \
crypto/hmac \ crypto/hmac \
os/user \
strconv \ strconv \
text/template/parse \ text/template/parse \
$(nil) $(nil)
@@ -503,17 +485,8 @@ tinygo-baremetal:
# regression test for #2666: e.g. encoding/hex must pass on baremetal # regression test for #2666: e.g. encoding/hex must pass on baremetal
$(TINYGO) test -target cortex-m-qemu encoding/hex $(TINYGO) test -target cortex-m-qemu encoding/hex
.PHONY: testchdir
testchdir:
# test 'build' command with{,out} -C argument
$(TINYGO) build -C tests/testing/chdir chdir.go && rm tests/testing/chdir/chdir
$(TINYGO) build ./tests/testing/chdir/chdir.go && rm chdir
# test 'run' command with{,out} -C argument
EXPECT_DIR=$(PWD)/tests/testing/chdir $(TINYGO) run -C tests/testing/chdir chdir.go
EXPECT_DIR=$(PWD) $(TINYGO) run ./tests/testing/chdir/chdir.go
.PHONY: smoketest .PHONY: smoketest
smoketest: testchdir smoketest:
$(TINYGO) version $(TINYGO) version
$(TINYGO) targets > /dev/null $(TINYGO) targets > /dev/null
# regression test for #2892 # regression test for #2892
@@ -671,8 +644,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1 $(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=rak4631 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac $(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/dac $(TINYGO) build -size short -o test.hex -target=pyportal examples/dac
@@ -835,20 +806,12 @@ ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest $(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
endif endif
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest $(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest $(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest $(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32-c3-devkit-rust-1 examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1 $(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@@ -893,7 +856,6 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
@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/macos-minimal-sdk
@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-crt/stdio
@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
@mkdir -p build/release/tinygo/lib/musl/crt @mkdir -p build/release/tinygo/lib/musl/crt
@@ -905,6 +867,9 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch @mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src @mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@mkdir -p build/release/tinygo/lib/wasi-cli/ @mkdir -p build/release/tinygo/lib/wasi-cli/
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
@echo copying source files @echo copying source files
@cp -p build/tinygo$(EXE) build/release/tinygo/bin @cp -p build/tinygo$(EXE) build/release/tinygo/bin
ifneq ($(USE_SYSTEM_BINARYEN),1) ifneq ($(USE_SYSTEM_BINARYEN),1)
@@ -926,27 +891,22 @@ endif
@cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/fcntl build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/locale build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/multibyte 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
@cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/process build/release/tinygo/lib/musl/src
@cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt @cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common @cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common @cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/stdio/ucrt_* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/stdio
@cp -rp lib/mingw-w64/mingw-w64-headers/crt/ build/release/tinygo/lib/mingw-w64/mingw-w64-headers @cp -rp lib/mingw-w64/mingw-w64-headers/crt/ build/release/tinygo/lib/mingw-w64/mingw-w64-headers
@cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults @cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx @cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
@@ -972,6 +932,12 @@ endif
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins @cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
@cp -rp src build/release/tinygo/src @cp -rp src build/release/tinygo/src
@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/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/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/release/tinygo/bin/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/release/tinygo/bin/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
release: release:
tar -czf build/release.tar.gz -C build/release tinygo tar -czf build/release.tar.gz -C build/release tinygo
@@ -991,31 +957,18 @@ endif
.PHONY: tools .PHONY: tools
tools: tools:
cd internal/tools && go generate -tags tools ./ go generate -C ./internal/tools -tags tools ./
.PHONY: lint .PHONY: lint
lint: tools ## Lint source tree lint:
revive -version go run github.com/mgechev/revive -version
# TODO: lint more directories! # TODO: lint more directories!
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here. # revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
# Can't use grep with friendly formatter. Plain output isn't too bad, though. # Can't use grep with friendly formatter. Plain output isn't too bad, though.
# Use 'grep .' to get rid of stray blank line # Use 'grep .' to get rid of stray blank line
revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}' go run github.com/mgechev/revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
SPELLDIRSCMD=find . -depth 1 -type d | egrep -wv '.git|lib|llvm|src'; find src -depth 1 | egrep -wv 'device|internal|net|vendor'; find src/internal -depth 1 -type d | egrep -wv src/internal/wasi
.PHONY: spell .PHONY: spell
spell: tools ## Spellcheck source tree spell:
misspell -error --dict misspell.csv -i 'ackward,devided,extint,rela' $$( $(SPELLDIRSCMD) ) *.go *.md # Check for typos in comments. Skip git submodules etc.
go run github.com/client9/misspell/cmd/misspell -i 'ackward,devided,extint,inbetween,programmmer,rela' $$( find . -depth 1 -type d | egrep -w -v 'lib|llvm|src/net' )
.PHONY: spellfix
spellfix: tools ## Same as spell, but fixes what it finds
misspell -w --dict misspell.csv -i 'ackward,devided,extint,rela' $$( $(SPELLDIRSCMD) ) *.go *.md
# https://www.client9.com/self-documenting-makefiles/
.PHONY: help
help:
@awk -F ':|##' '/^[^\t].+?:.*?##/ {\
gsub(/\$$\(LLVM_BUILDDIR\)/, "$(LLVM_BUILDDIR)"); \
printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \
}' $(MAKEFILE_LIST)
#.DEFAULT_GOAL=help
-32
View File
@@ -1,32 +0,0 @@
TinyGo Team Members
===================
The team of humans who maintain TinyGo.
* **Purpose**: To maintain the community, code, documentation, and tools for the TinyGo compiler.
* **Board**: The group of people who share responsibility for key decisions for the TinyGo organization.
* **Majority Voting**: The board makes decisions by majority vote.
* **Membership**: The board elects its own members.
* **Do-ocracy**: Those who step forward to do a given task propose how it should be done. Then other interested people can make comments.
* **Proof of Work**: Power in decision-making is slightly weighted based on a participant's labor for the community.
* **Initiation**: We need to establish a procedure for how people join the team of maintainers.
* **Transparency**: Important information should be made publicly available, ideally in a way that allows for public comment.
* **Code of Conduct**: Participants agree to abide by the current project Code of Conduct.
## Members
* Ayke van Laethem (@aykevl)
* Daniel Esteban (@conejoninja)
* Ron Evans (@deadprogram)
* Damian Gryski (@dgryski)
* Masaaki Takasago (@sago35)
* Patricio Whittingslow (@soypat)
* Yurii Soldak (@ysoldak)
## Experimental
* **Monthly Meeting**: A monthly meeting for the team and any other interested participants.
Duration: 1 hour
Facilitation: @deadprogram
Schedule: See https://github.com/tinygo-org/tinygo/wiki/Meetings for more information
+3 -3
View File
@@ -16,7 +16,7 @@ import (
"github.com/blakesmith/ar" "github.com/blakesmith/ar"
) )
// makeArchive creates an archive 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...>
@@ -150,7 +150,7 @@ func makeArchive(arfile *os.File, objs []string) error {
} }
// Keep track of the start of the symbol table. // Keep track of the start of the symbol table.
symbolTableStart, err := arfile.Seek(0, io.SeekCurrent) symbolTableStart, err := arfile.Seek(0, os.SEEK_CUR)
if err != nil { if err != nil {
return err return err
} }
@@ -172,7 +172,7 @@ func makeArchive(arfile *os.File, objs []string) error {
// Store the start index, for when we'll update the symbol table with // Store the start index, for when we'll update the symbol table with
// the correct file start indices. // the correct file start indices.
offset, err := arfile.Seek(0, io.SeekCurrent) offset, err := arfile.Seek(0, os.SEEK_CUR)
if err != nil { if err != nil {
return err return err
} }
+24 -32
View File
@@ -148,7 +148,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
job := makeDarwinLibSystemJob(config, tmpdir) job := makeDarwinLibSystemJob(config, tmpdir)
libcDependencies = append(libcDependencies, job) libcDependencies = append(libcDependencies, job)
case "musl": case "musl":
job, unlock, err := libMusl.load(config, tmpdir) job, unlock, err := Musl.load(config, tmpdir)
if err != nil { if err != nil {
return BuildResult{}, err return BuildResult{}, err
} }
@@ -156,7 +156,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o"))) libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
libcDependencies = append(libcDependencies, job) libcDependencies = append(libcDependencies, job)
case "picolibc": case "picolibc":
libcJob, unlock, err := libPicolibc.load(config, tmpdir) libcJob, unlock, err := Picolibc.load(config, tmpdir)
if err != nil { if err != nil {
return BuildResult{}, err return BuildResult{}, err
} }
@@ -169,19 +169,18 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
} }
libcDependencies = append(libcDependencies, dummyCompileJob(path)) libcDependencies = append(libcDependencies, dummyCompileJob(path))
case "wasmbuiltins": case "wasmbuiltins":
libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir) libcJob, unlock, err := WasmBuiltins.load(config, tmpdir)
if err != nil { if err != nil {
return BuildResult{}, err return BuildResult{}, err
} }
defer unlock() defer unlock()
libcDependencies = append(libcDependencies, libcJob) libcDependencies = append(libcDependencies, libcJob)
case "mingw-w64": case "mingw-w64":
job, unlock, err := libMinGW.load(config, tmpdir) _, unlock, err := MinGW.load(config, tmpdir)
if err != nil { if err != nil {
return BuildResult{}, err return BuildResult{}, err
} }
defer unlock() unlock()
libcDependencies = append(libcDependencies, job)
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(tmpdir, config.GOARCH())...) libcDependencies = append(libcDependencies, makeMinGWExtraLibs(tmpdir, config.GOARCH())...)
case "": case "":
// no library specified, so nothing to do // no library specified, so nothing to do
@@ -197,7 +196,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
ABI: config.ABI(), ABI: config.ABI(),
GOOS: config.GOOS(), GOOS: config.GOOS(),
GOARCH: config.GOARCH(), GOARCH: config.GOARCH(),
BuildMode: config.BuildMode(),
CodeModel: config.CodeModel(), CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(), RelocationModel: config.RelocationModel(),
SizeLevel: sizeLevel, SizeLevel: sizeLevel,
@@ -650,17 +648,10 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
result.Binary = result.Executable // final file result.Binary = result.Executable // final file
ldflags := append(config.LDFlags(), "-o", result.Executable) ldflags := append(config.LDFlags(), "-o", result.Executable)
if config.Options.BuildMode == "c-shared" {
if !strings.HasPrefix(config.Triple(), "wasm32-") {
return result, fmt.Errorf("buildmode c-shared is only supported on wasm at the moment")
}
ldflags = append(ldflags, "--no-entry")
}
// Add compiler-rt dependency if needed. Usually this is a simple load from // Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache. // a cache.
if config.Target.RTLib == "compiler-rt" { if config.Target.RTLib == "compiler-rt" {
job, unlock, err := libCompilerRT.load(config, tmpdir) job, unlock, err := CompilerRT.load(config, tmpdir)
if err != nil { if err != nil {
return result, err return result, err
} }
@@ -754,7 +745,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
ldflags = append(ldflags, dependency.result) ldflags = append(ldflags, dependency.result)
} }
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU()) ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
if config.GOOS() == "windows" { if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker. // Options for the MinGW wrapper for the lld COFF linker.
ldflags = append(ldflags, ldflags = append(ldflags,
@@ -788,7 +778,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
} }
err = link(config.Target.Linker, ldflags...) err = link(config.Target.Linker, ldflags...)
if err != nil { if err != nil {
return err return &commandError{"failed to link", result.Executable, err}
} }
var calculatedStacks []string var calculatedStacks []string
@@ -831,13 +821,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
args = append(args, "--asyncify") args = append(args, "--asyncify")
} }
inputFile := result.Binary exeunopt := result.Executable
result.Binary = result.Executable + ".wasmopt"
if config.Options.Work {
// Keep the work direction around => don't overwrite the .wasm binary with the optimized version
exeunopt += ".pre-wasm-opt"
os.Rename(result.Executable, exeunopt)
}
args = append(args, args = append(args,
opt, opt,
"-g", "-g",
inputFile, exeunopt,
"--output", result.Binary, "--output", result.Executable,
) )
wasmopt := goenv.Get("WASMOPT") wasmopt := goenv.Get("WASMOPT")
@@ -867,15 +863,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// wasm-tools component embed -w wasi:cli/command // wasm-tools component embed -w wasi:cli/command
// $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm // $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm
componentEmbedInputFile := result.Binary
result.Binary = result.Executable + ".wasm-component-embed"
args := []string{ args := []string{
"component", "component",
"embed", "embed",
"-w", witWorld, "-w", witWorld,
witPackage, witPackage,
componentEmbedInputFile, result.Executable,
"-o", result.Binary, "-o", result.Executable,
} }
wasmtools := goenv.Get("WASMTOOLS") wasmtools := goenv.Get("WASMTOOLS")
@@ -888,17 +882,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("`wasm-tools component embed` failed: %w", err) return fmt.Errorf("wasm-tools failed: %w", err)
} }
// wasm-tools component new embedded.wasm -o component.wasm // wasm-tools component new embedded.wasm -o component.wasm
componentNewInputFile := result.Binary
result.Binary = result.Executable + ".wasm-component-new"
args = []string{ args = []string{
"component", "component",
"new", "new",
componentNewInputFile, result.Executable,
"-o", result.Binary, "-o", result.Executable,
} }
if config.Options.PrintCommands != nil { if config.Options.PrintCommands != nil {
@@ -910,7 +902,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("`wasm-tools component new` failed: %w", err) return fmt.Errorf("wasm-tools failed: %w", err)
} }
} }
@@ -1265,7 +1257,7 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
} }
// Goroutines need to be started and finished and take up some stack space // Goroutines need to be started and finished and take up some stack space
// that way. This can be measured by measuring the stack size of // that way. This can be measured by measuing the stack size of
// tinygo_startTask. // tinygo_startTask.
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 { if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs) return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
+6 -13
View File
@@ -53,30 +53,23 @@ func TestClangAttributes(t *testing.T) {
for _, options := range []*compileopts.Options{ for _, options := range []*compileopts.Options{
{GOOS: "linux", GOARCH: "386"}, {GOOS: "linux", GOARCH: "386"},
{GOOS: "linux", GOARCH: "amd64"}, {GOOS: "linux", GOARCH: "amd64"},
{GOOS: "linux", GOARCH: "arm", GOARM: "5,softfloat"}, {GOOS: "linux", GOARCH: "arm", GOARM: "5"},
{GOOS: "linux", GOARCH: "arm", GOARM: "6,softfloat"}, {GOOS: "linux", GOARCH: "arm", GOARM: "6"},
{GOOS: "linux", GOARCH: "arm", GOARM: "7,softfloat"}, {GOOS: "linux", GOARCH: "arm", GOARM: "7"},
{GOOS: "linux", GOARCH: "arm", GOARM: "5,hardfloat"},
{GOOS: "linux", GOARCH: "arm", GOARM: "6,hardfloat"},
{GOOS: "linux", GOARCH: "arm", GOARM: "7,hardfloat"},
{GOOS: "linux", GOARCH: "arm64"}, {GOOS: "linux", GOARCH: "arm64"},
{GOOS: "linux", GOARCH: "mips", GOMIPS: "hardfloat"}, {GOOS: "linux", GOARCH: "mips"},
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "hardfloat"}, {GOOS: "linux", GOARCH: "mipsle"},
{GOOS: "linux", GOARCH: "mips", GOMIPS: "softfloat"},
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "softfloat"},
{GOOS: "darwin", GOARCH: "amd64"}, {GOOS: "darwin", GOARCH: "amd64"},
{GOOS: "darwin", GOARCH: "arm64"}, {GOOS: "darwin", GOARCH: "arm64"},
{GOOS: "windows", GOARCH: "amd64"}, {GOOS: "windows", GOARCH: "amd64"},
{GOOS: "windows", GOARCH: "arm64"}, {GOOS: "windows", GOARCH: "arm64"},
{GOOS: "wasip1", GOARCH: "wasm"}, {GOOS: "wasip1", GOARCH: "wasm"},
{GOOS: "wasip2", GOARCH: "wasm"},
} { } {
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
if options.GOARCH == "arm" { if options.GOARCH == "arm" {
name += ",GOARM=" + options.GOARM name += ",GOARM=" + options.GOARM
} }
if options.GOARCH == "mips" || options.GOARCH == "mipsle" {
name += ",GOMIPS=" + options.GOMIPS
}
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
testClangAttributes(t, options) testClangAttributes(t, options)
}) })
+7 -41
View File
@@ -3,8 +3,8 @@ package builder
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
@@ -132,38 +132,6 @@ var genericBuiltins = []string{
"umodti3.c", "umodti3.c",
} }
// These are the GENERIC_TF_SOURCES as of LLVM 18.
// They are not needed on all platforms (32-bit platforms usually don't need
// these) but they seem to compile fine so it's easier to include them.
var genericBuiltins128 = []string{
"addtf3.c",
"comparetf2.c",
"divtc3.c",
"divtf3.c",
"extenddftf2.c",
"extendhftf2.c",
"extendsftf2.c",
"fixtfdi.c",
"fixtfsi.c",
"fixtfti.c",
"fixunstfdi.c",
"fixunstfsi.c",
"fixunstfti.c",
"floatditf.c",
"floatsitf.c",
"floattitf.c",
"floatunditf.c",
"floatunsitf.c",
"floatuntitf.c",
"multc3.c",
"multf3.c",
"powitf2.c",
"subtf3.c",
"trunctfdf2.c",
"trunctfhf2.c",
"trunctfsf2.c",
}
var aeabiBuiltins = []string{ var aeabiBuiltins = []string{
"arm/aeabi_cdcmp.S", "arm/aeabi_cdcmp.S",
"arm/aeabi_cdcmpeq_check_nan.c", "arm/aeabi_cdcmpeq_check_nan.c",
@@ -201,12 +169,12 @@ var avrBuiltins = []string{
"avr/udivmodqi4.S", "avr/udivmodqi4.S",
} }
// libCompilerRT is a library with symbols required by programs compiled with // CompilerRT is a library with symbols required by programs compiled with LLVM.
// LLVM. These symbols are for operations that cannot be emitted with a single // These symbols are for operations that cannot be emitted with a single
// instruction or a short sequence of instructions for that target. // instruction or a short sequence of instructions for that target.
// //
// For more information, see: https://compiler-rt.llvm.org/ // For more information, see: https://compiler-rt.llvm.org/
var libCompilerRT = Library{ var CompilerRT = Library{
name: "compiler-rt", name: "compiler-rt",
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"}
@@ -222,13 +190,11 @@ var libCompilerRT = Library{
}, },
librarySources: func(target string) ([]string, error) { librarySources: func(target string) ([]string, error) {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
switch compileopts.CanonicalArchName(target) { if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
case "arm":
builtins = append(builtins, aeabiBuiltins...) builtins = append(builtins, aeabiBuiltins...)
case "avr": }
if strings.HasPrefix(target, "avr") {
builtins = append(builtins, avrBuiltins...) builtins = append(builtins, avrBuiltins...)
case "x86_64", "aarch64", "riscv64": // any 64-bit arch
builtins = append(builtins, genericBuiltins128...)
} }
return builtins, nil return builtins, nil
}, },
+1 -1
View File
@@ -93,7 +93,7 @@ struct AssemblerInvocation {
EmitDwarfUnwindType EmitDwarfUnwind; EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries. // Whether to emit compact-unwind for non-canonical entries.
// Note: maybe overridden by other constraints. // Note: maybe overriden by other constraints.
unsigned EmitCompactUnwindNonCanonical : 1; unsigned EmitCompactUnwindNonCanonical : 1;
/// The name of the relocation model to use. /// The name of the relocation model to use.
+12
View File
@@ -3,6 +3,7 @@ package builder
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"runtime" "runtime"
"strings" "strings"
@@ -75,3 +76,14 @@ func LookupCommand(name string) (string, error) {
} }
return "", errors.New("none of these commands were found in your $PATH: " + strings.Join(commands[name], " ")) return "", errors.New("none of these commands were found in your $PATH: " + strings.Join(commands[name], " "))
} }
func execCommand(name string, args ...string) error {
name, err := LookupCommand(name)
if err != nil {
return err
}
cmd := exec.Command(name, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
+4 -22
View File
@@ -2,7 +2,6 @@ package builder
import ( import (
"fmt" "fmt"
"runtime"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
@@ -24,37 +23,20 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
spec.OpenOCDCommands = options.OpenOCDCommands spec.OpenOCDCommands = options.OpenOCDCommands
} }
// Version range supported by TinyGo. major, minor, err := goenv.GetGorootVersion()
const minorMin = 19
const minorMax = 23
// Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax { if major != 1 || minor < 19 || minor > 22 {
// Note: when this gets updated, also update the Go compatibility matrix: // Note: when this gets updated, also update the Go compatibility matrix:
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md // https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.19 through 1.23, got go%d.%d", gorootMajor, gorootMinor) return nil, fmt.Errorf("requires go version 1.19 through 1.22, got go%d.%d", major, minor)
}
// Check that the Go toolchain version isn't too new, if we haven't been
// compiled with the latest Go version.
// This may be a bit too aggressive: if the newer version doesn't change the
// Go language we will most likely be able to compile it.
buildMajor, buildMinor, _, err := goenv.Parse(runtime.Version())
if err != nil {
return nil, err
}
if buildMajor != 1 || buildMinor < gorootMinor {
return nil, fmt.Errorf("cannot compile with Go toolchain version go%d.%d (TinyGo was built using toolchain version %s)", gorootMajor, gorootMinor, runtime.Version())
} }
return &compileopts.Config{ return &compileopts.Config{
Options: options, Options: options,
Target: spec, Target: spec,
GoMinorVersion: gorootMinor, GoMinorVersion: minor,
TestConfig: options.TestConfig, TestConfig: options.TestConfig,
}, nil }, nil
} }
+2 -2
View File
@@ -15,12 +15,12 @@ func (e *MultiError) Error() string {
// newMultiError returns a *MultiError if there is more than one error, or // newMultiError returns a *MultiError if there is more than one error, or
// returns that error directly when there is only one. Passing an empty slice // returns that error directly when there is only one. Passing an empty slice
// will return nil (because there is no error). // will lead to a panic.
// The importPath may be passed if this error is for a single package. // The importPath may be passed if this error is for a single package.
func newMultiError(errs []error, importPath string) error { func newMultiError(errs []error, importPath string) error {
switch len(errs) { switch len(errs) {
case 0: case 0:
return nil panic("attempted to create empty MultiError")
case 1: case 1:
return errs[0] return errs[0]
default: default:
+16 -6
View File
@@ -17,6 +17,14 @@ import (
// concurrency or performance issues. // concurrency or performance issues.
const jobRunnerDebug = false const jobRunnerDebug = false
type jobState uint8
const (
jobStateQueued jobState = iota // not yet running
jobStateRunning // running
jobStateFinished // finished running
)
// compileJob is a single compiler job, comparable to a single Makefile target. // compileJob is a single compiler job, comparable to a single Makefile target.
// It is used to orchestrate various compiler tasks that can be run in parallel // It is used to orchestrate various compiler tasks that can be run in parallel
// but that have dependencies and thus have limitations in how they can be run. // but that have dependencies and thus have limitations in how they can be run.
@@ -47,11 +55,12 @@ func dummyCompileJob(result string) *compileJob {
// ordered as such in the job dependencies. // ordered as such in the job dependencies.
func runJobs(job *compileJob, sema chan struct{}) error { func runJobs(job *compileJob, sema chan struct{}) error {
if sema == nil { if sema == nil {
// Have a default, if the semaphore isn't set. This is useful for tests. // Have a default, if the semaphore isn't set. This is useful for
// tests.
sema = make(chan struct{}, runtime.NumCPU()) sema = make(chan struct{}, runtime.NumCPU())
} }
if cap(sema) == 0 { if cap(sema) == 0 {
return errors.New("cannot run 0 jobs at a time") return errors.New("cannot 0 jobs at a time")
} }
// Create a slice of jobs to run, where all dependencies are run in order. // Create a slice of jobs to run, where all dependencies are run in order.
@@ -72,10 +81,10 @@ func runJobs(job *compileJob, sema chan struct{}) error {
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs)) waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
dependents := make(map[*compileJob][]*compileJob, len(jobs)) dependents := make(map[*compileJob][]*compileJob, len(jobs))
compileJobs := make(map[*compileJob]int) jidx := make(map[*compileJob]int)
var ready intHeap var ready intHeap
for i, job := range jobs { for i, job := range jobs {
compileJobs[job] = i jidx[job] = i
if len(job.dependencies) == 0 { if len(job.dependencies) == 0 {
// This job is ready to run. // This job is ready to run.
ready.Push(i) ready.Push(i)
@@ -96,7 +105,8 @@ func runJobs(job *compileJob, sema chan struct{}) error {
// Create a channel to accept notifications of completion. // Create a channel to accept notifications of completion.
doneChan := make(chan *compileJob) doneChan := make(chan *compileJob)
// Send each job in the jobs slice to a worker, taking care of job dependencies. // Send each job in the jobs slice to a worker, taking care of job
// dependencies.
numRunningJobs := 0 numRunningJobs := 0
var totalTime time.Duration var totalTime time.Duration
start := time.Now() start := time.Now()
@@ -146,7 +156,7 @@ func runJobs(job *compileJob, sema chan struct{}) error {
delete(wait, completed) delete(wait, completed)
if len(wait) == 0 { if len(wait) == 0 {
// This job is now ready to run. // This job is now ready to run.
ready.Push(compileJobs[j]) ready.Push(jidx[j])
delete(waiting, j) delete(waiting, j)
} }
} }
+24 -20
View File
@@ -35,6 +35,19 @@ type Library struct {
crt1Source string crt1Source string
} }
// Load the library archive, possibly generating and caching it if needed.
// The resulting directory may be stored in the provided tmpdir, which is
// expected to be removed after the Load call.
func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
job, unlock, err := l.load(config, tmpdir)
if err != nil {
return "", err
}
defer unlock()
err = runJobs(job, config.Options.Semaphore)
return filepath.Dir(job.result), err
}
// load returns a compile job to build this library file for the given target // load returns a compile job to build this library file for the given target
// and CPU. It may return a dummy compileJob if the library build is already // and CPU. It may return a dummy compileJob if the library build is already
// cached. The path is stored as job.result but is only valid after the job has // cached. The path is stored as job.result but is only valid after the job has
@@ -149,37 +162,28 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if config.ABI() != "" { if config.ABI() != "" {
args = append(args, "-mabi="+config.ABI()) args = append(args, "-mabi="+config.ABI())
} }
switch compileopts.CanonicalArchName(target) { if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
case "arm":
if strings.Split(target, "-")[2] == "linux" { if strings.Split(target, "-")[2] == "linux" {
args = append(args, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables") args = append(args, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
} else { } else {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables") args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
} }
case "avr": }
if strings.HasPrefix(target, "avr") {
// AVR defaults to C float and double both being 32-bit. This deviates // 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 // from what most code (and certainly compiler-rt) expects. So we need
// to force the compiler to use 64-bit floating point numbers for // to force the compiler to use 64-bit floating point numbers for
// double. // double.
args = append(args, "-mdouble=64") args = append(args, "-mdouble=64")
case "riscv32":
args = append(args, "-march=rv32imac", "-fforce-enable-int128")
case "riscv64":
args = append(args, "-march=rv64gc")
case "mips":
args = append(args, "-fno-pic")
} }
if config.Target.SoftFloat { if strings.HasPrefix(target, "riscv32-") {
// Use softfloat instead of floating point instructions. This is args = append(args, "-march=rv32imac", "-fforce-enable-int128")
// supported on many architectures. }
args = append(args, "-msoft-float") if strings.HasPrefix(target, "riscv64-") {
} else { args = append(args, "-march=rv64gc")
if strings.HasPrefix(target, "armv5") { }
// On ARMv5 we need to explicitly enable hardware floating point if strings.HasPrefix(target, "mips") {
// instructions: Clang appears to assume the hardware doesn't have a args = append(args, "-fno-pic")
// FPU otherwise.
args = append(args, "-mfpu=vfpv2")
}
} }
var once sync.Once var once sync.Once
+6 -22
View File
@@ -10,7 +10,7 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
var libMinGW = Library{ var MinGW = Library{
name: "mingw-w64", name: "mingw-w64",
makeHeaders: func(target, includeDir string) error { makeHeaders: func(target, includeDir string) error {
// copy _mingw.h // copy _mingw.h
@@ -27,30 +27,14 @@ var libMinGW = Library{
_, err = io.Copy(outf, inf) _, err = io.Copy(outf, inf)
return err return err
}, },
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64") }, sourceDir: func() string { return "" }, // unused
cflags: func(target, headerPath string) []string { cflags: func(target, headerPath string) []string {
mingwDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64") // No flags necessary because there are no files to compile.
return []string{ return nil
"-nostdlibinc",
"-isystem", mingwDir + "/mingw-w64-headers/crt",
"-I", mingwDir + "/mingw-w64-headers/defaults/include",
"-I" + headerPath,
}
}, },
librarySources: func(target string) ([]string, error) { librarySources: func(target string) ([]string, error) {
// These files are needed so that printf and the like are supported. // We only use the UCRT DLL file. No source files necessary.
sources := []string{ return nil, nil
"mingw-w64-crt/stdio/ucrt_fprintf.c",
"mingw-w64-crt/stdio/ucrt_fwprintf.c",
"mingw-w64-crt/stdio/ucrt_printf.c",
"mingw-w64-crt/stdio/ucrt_snprintf.c",
"mingw-w64-crt/stdio/ucrt_sprintf.c",
"mingw-w64-crt/stdio/ucrt_vfprintf.c",
"mingw-w64-crt/stdio/ucrt_vprintf.c",
"mingw-w64-crt/stdio/ucrt_vsnprintf.c",
"mingw-w64-crt/stdio/ucrt_vsprintf.c",
}
return sources, nil
}, },
} }
+1 -15
View File
@@ -12,7 +12,7 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
var libMusl = Library{ var Musl = Library{
name: "musl", name: "musl",
makeHeaders: func(target, includeDir string) error { makeHeaders: func(target, includeDir string) error {
bits := filepath.Join(includeDir, "bits") bits := filepath.Join(includeDir, "bits")
@@ -92,8 +92,6 @@ var libMusl = Library{
"-Wno-ignored-pragmas", "-Wno-ignored-pragmas",
"-Wno-tautological-constant-out-of-range-compare", "-Wno-tautological-constant-out-of-range-compare",
"-Wno-deprecated-non-prototype", "-Wno-deprecated-non-prototype",
"-Wno-format",
"-Wno-parentheses",
"-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),
@@ -116,20 +114,16 @@ var libMusl = Library{
"env/*.c", "env/*.c",
"errno/*.c", "errno/*.c",
"exit/*.c", "exit/*.c",
"fcntl/*.c",
"internal/defsysinfo.c", "internal/defsysinfo.c",
"internal/libc.c", "internal/libc.c",
"internal/syscall_ret.c", "internal/syscall_ret.c",
"internal/vdso.c", "internal/vdso.c",
"legacy/*.c", "legacy/*.c",
"locale/*.c",
"linux/*.c", "linux/*.c",
"malloc/*.c", "malloc/*.c",
"malloc/mallocng/*.c", "malloc/mallocng/*.c",
"mman/*.c", "mman/*.c",
"math/*.c", "math/*.c",
"multibyte/*.c",
"signal/" + arch + "/*.s",
"signal/*.c", "signal/*.c",
"stdio/*.c", "stdio/*.c",
"string/*.c", "string/*.c",
@@ -137,20 +131,12 @@ var libMusl = Library{
"thread/*.c", "thread/*.c",
"time/*.c", "time/*.c",
"unistd/*.c", "unistd/*.c",
"process/*.c",
} }
if arch == "arm" { if arch == "arm" {
// These files need to be added to the start for some reason. // These files need to be added to the start for some reason.
globs = append([]string{"thread/arm/*.c"}, globs...) globs = append([]string{"thread/arm/*.c"}, globs...)
} }
if arch != "aarch64" && arch != "mips" {
//aarch64 and mips have no architecture specific code, either they
// are not supported or don't need any?
globs = append([]string{"process/" + arch + "/*.s"}, globs...)
}
var sources []string var sources []string
seenSources := map[string]struct{}{} seenSources := map[string]struct{}{}
basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/" basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/"
+2 -3
View File
@@ -8,9 +8,9 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
// libPicolibc is a C library for bare metal embedded devices. It was originally // Picolibc is a C library for bare metal embedded devices. It was originally
// based on newlib. // based on newlib.
var libPicolibc = Library{ var Picolibc = Library{
name: "picolibc", name: "picolibc",
makeHeaders: func(target, includeDir string) error { makeHeaders: func(target, includeDir string) error {
f, err := os.Create(filepath.Join(includeDir, "picolibc.h")) f, err := os.Create(filepath.Join(includeDir, "picolibc.h"))
@@ -29,7 +29,6 @@ var libPicolibc = Library{
"-D_HAVE_ALIAS_ATTRIBUTE", "-D_HAVE_ALIAS_ATTRIBUTE",
"-DTINY_STDIO", "-DTINY_STDIO",
"-DPOSIX_IO", "-DPOSIX_IO",
"-DFORMAT_DEFAULT_INTEGER", // use __i_vfprintf and __i_vfscanf by default
"-D_IEEE_LIBM", "-D_IEEE_LIBM",
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU "-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
"-D__OBSOLETE_MATH_DOUBLE=0", "-D__OBSOLETE_MATH_DOUBLE=0",
+3 -3
View File
@@ -41,9 +41,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test. // This is a small number of very diverse targets that we want to test.
tests := []sizeTest{ tests := []sizeTest{
// microcontrollers // microcontrollers
{"hifive1b", "examples/echo", 4600, 280, 0, 2268}, {"hifive1b", "examples/echo", 4484, 280, 0, 2252},
{"microbit", "examples/serial", 2908, 388, 8, 2272}, {"microbit", "examples/serial", 2732, 388, 8, 2256},
{"wioterminal", "examples/pininterrupt", 6140, 1484, 116, 6832}, {"wioterminal", "examples/pininterrupt", 6016, 1484, 116, 6816},
// TODO: also check wasm. Right now this is difficult, because // TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the // wasm binaries are run through wasm-opt and therefore the
+22 -169
View File
@@ -1,191 +1,44 @@
package builder package builder
import ( import (
"bytes"
"fmt"
"go/scanner"
"go/token"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strconv" "github.com/tinygo-org/tinygo/goenv"
"strings"
) )
// runCCompiler invokes a C compiler with the given arguments. // runCCompiler invokes a C compiler with the given arguments.
func runCCompiler(flags ...string) error { func runCCompiler(flags ...string) error {
// Find the right command to run Clang.
var cmd *exec.Cmd
if hasBuiltinTools { if hasBuiltinTools {
// Compile this with the internal Clang compiler. // Compile this with the internal Clang compiler.
cmd = exec.Command(os.Args[0], append([]string{"clang"}, flags...)...) cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
} else { cmd.Stdout = os.Stdout
// Compile this with an external invocation of the Clang compiler. cmd.Stderr = os.Stderr
name, err := LookupCommand("clang") return cmd.Run()
if err != nil {
return err
}
cmd = exec.Command(name, flags...)
} }
cmd.Stdout = os.Stdout // Compile this with an external invocation of the Clang compiler.
cmd.Stderr = os.Stderr return execCommand("clang", flags...)
// Make sure the command doesn't use any environmental variables.
// Most importantly, it should not use C_INCLUDE_PATH and the like.
cmd.Env = []string{}
// Let some environment variables through. One important one is the
// temporary directory, especially on Windows it looks like Clang breaks if
// the temporary directory has not been set.
// See: https://github.com/tinygo-org/tinygo/issues/4557
// Also see: https://github.com/llvm/llvm-project/blob/release/18.x/llvm/lib/Support/Unix/Path.inc#L1435
for _, env := range os.Environ() {
// We could parse the key and look it up in a map, but since there are
// only a few keys iterating through them is easier and maybe even
// faster.
for _, prefix := range []string{"TMPDIR=", "TMP=", "TEMP=", "TEMPDIR="} {
if strings.HasPrefix(env, prefix) {
cmd.Env = append(cmd.Env, env)
break
}
}
}
return cmd.Run()
} }
// link invokes a linker with the given name and flags. // link invokes a linker with the given name and flags.
func link(linker string, flags ...string) error { func link(linker string, flags ...string) error {
// We only support LLD. if hasBuiltinTools && (linker == "ld.lld" || linker == "wasm-ld") {
if linker != "ld.lld" && linker != "wasm-ld" { // Run command with internal linker.
return fmt.Errorf("unexpected: linker %s should be ld.lld or wasm-ld", linker) cmd := exec.Command(os.Args[0], append([]string{linker}, flags...)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
} }
var cmd *exec.Cmd // Fall back to external command.
if hasBuiltinTools { if _, ok := commands[linker]; ok {
cmd = exec.Command(os.Args[0], append([]string{linker}, flags...)...) return execCommand(linker, flags...)
} else {
name, err := LookupCommand(linker)
if err != nil {
return err
}
cmd = exec.Command(name, flags...)
} }
var buf bytes.Buffer
cmd := exec.Command(linker, flags...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = &buf cmd.Stderr = os.Stderr
err := cmd.Run() cmd.Dir = goenv.Get("TINYGOROOT")
if err != nil { return cmd.Run()
if buf.Len() == 0 {
// The linker failed but there was no output.
// Therefore, show some output anyway.
return fmt.Errorf("failed to run linker: %w", err)
}
return parseLLDErrors(buf.String())
}
return nil
}
// Split LLD errors into individual erros (including errors that continue on the
// next line, using a ">>>" prefix). If possible, replace the raw errors with a
// more user-friendly version (and one that's more in a Go style).
func parseLLDErrors(text string) error {
// Split linker output in separate error messages.
lines := strings.Split(text, "\n")
var errorLines []string // one or more line (belonging to a single error) per line
for _, line := range lines {
line = strings.TrimRight(line, "\r") // needed for Windows
if len(errorLines) != 0 && strings.HasPrefix(line, ">>> ") {
errorLines[len(errorLines)-1] += "\n" + line
continue
}
if line == "" {
continue
}
errorLines = append(errorLines, line)
}
// Parse error messages.
var linkErrors []error
var flashOverflow, ramOverflow uint64
for _, message := range errorLines {
parsedError := false
// Check for undefined symbols.
// This can happen in some cases like with CGo and //go:linkname tricker.
if matches := regexp.MustCompile(`^ld.lld: error: undefined symbol: (.*)\n`).FindStringSubmatch(message); matches != nil {
symbolName := matches[1]
for _, line := range strings.Split(message, "\n") {
matches := regexp.MustCompile(`referenced by .* \(((.*):([0-9]+))\)`).FindStringSubmatch(line)
if matches != nil {
parsedError = true
line, _ := strconv.Atoi(matches[3])
// TODO: detect common mistakes like -gc=none?
linkErrors = append(linkErrors, scanner.Error{
Pos: token.Position{
Filename: matches[2],
Line: line,
},
Msg: "linker could not find symbol " + symbolName,
})
}
}
}
// Check for flash/RAM overflow.
if matches := regexp.MustCompile(`^ld.lld: error: section '(.*?)' will not fit in region '(.*?)': overflowed by ([0-9]+) bytes$`).FindStringSubmatch(message); matches != nil {
region := matches[2]
n, err := strconv.ParseUint(matches[3], 10, 64)
if err != nil {
// Should not happen at all (unless it overflows an uint64 for some reason).
continue
}
// Check which area overflowed.
// Some chips use differently named memory areas, but these are by
// far the most common.
switch region {
case "FLASH_TEXT":
if n > flashOverflow {
flashOverflow = n
}
parsedError = true
case "RAM":
if n > ramOverflow {
ramOverflow = n
}
parsedError = true
}
}
// If we couldn't parse the linker error: show the error as-is to
// the user.
if !parsedError {
linkErrors = append(linkErrors, LinkerError{message})
}
}
if flashOverflow > 0 {
linkErrors = append(linkErrors, LinkerError{
Msg: fmt.Sprintf("program too large for this chip (flash overflowed by %d bytes)\n\toptimization guide: https://tinygo.org/docs/guides/optimizing-binaries/", flashOverflow),
})
}
if ramOverflow > 0 {
linkErrors = append(linkErrors, LinkerError{
Msg: fmt.Sprintf("program uses too much static RAM on this chip (RAM overflowed by %d bytes)", ramOverflow),
})
}
return newMultiError(linkErrors, "")
}
// LLD linker error that could not be parsed or doesn't refer to a source
// location.
type LinkerError struct {
Msg string
}
func (e LinkerError) Error() string {
return e.Msg
} }
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
var libWasmBuiltins = Library{ var WasmBuiltins = Library{
name: "wasmbuiltins", name: "wasmbuiltins",
makeHeaders: func(target, includeDir string) error { makeHeaders: func(target, includeDir string) error {
if err := os.Mkdir(includeDir+"/bits", 0o777); err != nil { if err := os.Mkdir(includeDir+"/bits", 0o777); err != nil {
+3 -10
View File
@@ -162,13 +162,6 @@ func __GoBytes(unsafe.Pointer, uintptr) []byte
func GoBytes(ptr unsafe.Pointer, length C.int) []byte { func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func __CBytes([]byte) unsafe.Pointer
func CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
` `
// Process extracts `import "C"` statements from the AST, parses the comment // Process extracts `import "C"` statements from the AST, parses the comment
@@ -225,7 +218,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
switch decl := decl.(type) { switch decl := decl.(type) {
case *ast.FuncDecl: case *ast.FuncDecl:
switch decl.Name.Name { switch decl.Name.Name {
case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes", "CBytes", "__CBytes": case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes":
// Adjust the name to have a "C." prefix so it is correctly // Adjust the name to have a "C." prefix so it is correctly
// resolved. // resolved.
decl.Name.Name = "C." + decl.Name.Name decl.Name.Name = "C." + decl.Name.Name
@@ -1148,7 +1141,7 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
if alias := cgoAliases["C."+name]; alias != "" { if alias := cgoAliases["C."+name]; alias != "" {
return alias return alias
} }
node := f.getASTDeclNode(name, found) node := f.getASTDeclNode(name, found, iscall)
if node, ok := node.(*ast.FuncDecl); ok { if node, ok := node.(*ast.FuncDecl); ok {
if !iscall { if !iscall {
return node.Name.Name + "$funcaddr" return node.Name.Name + "$funcaddr"
@@ -1160,7 +1153,7 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
// getASTDeclNode will declare the given C AST node (if not already defined) and // getASTDeclNode will declare the given C AST node (if not already defined) and
// returns it. // returns it.
func (f *cgoFile) getASTDeclNode(name string, found clangCursor) ast.Node { func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) ast.Node {
if node, ok := f.defined[name]; ok { if node, ok := f.defined[name]; ok {
// Declaration was found in the current file, so return it immediately. // Declaration was found in the current file, so return it immediately.
return node return node
+4 -136
View File
@@ -54,72 +54,8 @@ func init() {
} }
// parseConst parses the given string as a C constant. // parseConst parses the given string as a C constant.
func parseConst(pos token.Pos, fset *token.FileSet, value string, params []ast.Expr, callerPos token.Pos, f *cgoFile) (ast.Expr, *scanner.Error) { func parseConst(pos token.Pos, fset *token.FileSet, value string) (ast.Expr, *scanner.Error) {
t := newTokenizer(pos, fset, value, f) t := newTokenizer(pos, fset, value)
// If params is non-nil (could be a zero length slice), this const is
// actually a function-call like expression from another macro.
// This means we have to parse a string like "(a, b) (a+b)".
// We do this by parsing the parameters at the start and then treating the
// following like a normal constant expression.
if params != nil {
// Parse opening paren.
if t.curToken != token.LPAREN {
return nil, unexpectedToken(t, token.LPAREN)
}
t.Next()
// Parse parameters (identifiers) and closing paren.
var paramIdents []string
for i := 0; ; i++ {
if i == 0 && t.curToken == token.RPAREN {
// No parameters, break early.
t.Next()
break
}
// Read the parameter name.
if t.curToken != token.IDENT {
return nil, unexpectedToken(t, token.IDENT)
}
paramIdents = append(paramIdents, t.curValue)
t.Next()
// Read the next token: either a continuation (comma) or end of list
// (rparen).
if t.curToken == token.RPAREN {
// End of parameter list.
t.Next()
break
} else if t.curToken == token.COMMA {
// Comma, so there will be another parameter name.
t.Next()
} else {
return nil, &scanner.Error{
Pos: t.fset.Position(t.curPos),
Msg: "unexpected token " + t.curToken.String() + " inside macro parameters, expected ',' or ')'",
}
}
}
// Report an error if there is a mismatch in parameter length.
// The error is reported at the location of the closing paren from the
// caller location.
if len(params) != len(paramIdents) {
return nil, &scanner.Error{
Pos: t.fset.Position(callerPos),
Msg: fmt.Sprintf("unexpected number of parameters: expected %d, got %d", len(paramIdents), len(params)),
}
}
// Assign values to the parameters.
// These parameter names are closer in 'scope' than other identifiers so
// will be used first when parsing an identifier.
for i, name := range paramIdents {
t.params[name] = params[i]
}
}
expr, err := parseConstExpr(t, precedenceLowest) expr, err := parseConstExpr(t, precedenceLowest)
t.Next() t.Next()
if t.curToken != token.EOF { if t.curToken != token.EOF {
@@ -160,68 +96,6 @@ func parseConstExpr(t *tokenizer, precedence int) (ast.Expr, *scanner.Error) {
} }
func parseIdent(t *tokenizer) (ast.Expr, *scanner.Error) { func parseIdent(t *tokenizer) (ast.Expr, *scanner.Error) {
// If the identifier is one of the parameters of this function-like macro,
// use the parameter value.
if val, ok := t.params[t.curValue]; ok {
return val, nil
}
if t.f != nil {
// Check whether this identifier is actually a macro "call" with
// parameters. In that case, we should parse the parameters and pass it
// on to a new invocation of parseConst.
if t.peekToken == token.LPAREN {
if cursor, ok := t.f.names[t.curValue]; ok && t.f.isFunctionLikeMacro(cursor) {
// We know the current and peek tokens (the peek one is the '('
// token). So skip ahead until the current token is the first
// unknown token.
t.Next()
t.Next()
// Parse the list of parameters until ')' (rparen) is found.
params := []ast.Expr{}
for i := 0; ; i++ {
if i == 0 && t.curToken == token.RPAREN {
break
}
x, err := parseConstExpr(t, precedenceLowest)
if err != nil {
return nil, err
}
params = append(params, x)
t.Next()
if t.curToken == token.COMMA {
t.Next()
} else if t.curToken == token.RPAREN {
break
} else {
return nil, &scanner.Error{
Pos: t.fset.Position(t.curPos),
Msg: "unexpected token " + t.curToken.String() + ", ',' or ')'",
}
}
}
// Evaluate the macro value and use it as the identifier value.
rparen := t.curPos
pos, text := t.f.getMacro(cursor)
return parseConst(pos, t.fset, text, params, rparen, t.f)
}
}
// Normally the name is something defined in the file (like another
// macro) which we get the declaration from using getASTDeclName.
// This ensures that names that are only referenced inside a macro are
// still getting defined.
if cursor, ok := t.f.names[t.curValue]; ok {
return &ast.Ident{
NamePos: t.curPos,
Name: t.f.getASTDeclName(t.curValue, cursor, false),
}, nil
}
}
// t.f is nil during testing. This is a fallback.
return &ast.Ident{ return &ast.Ident{
NamePos: t.curPos, NamePos: t.curPos,
Name: "C." + t.curValue, Name: "C." + t.curValue,
@@ -290,25 +164,21 @@ func unexpectedToken(t *tokenizer, expected token.Token) *scanner.Error {
// tokenizer reads C source code and converts it to Go tokens. // tokenizer reads C source code and converts it to Go tokens.
type tokenizer struct { type tokenizer struct {
f *cgoFile
curPos, peekPos token.Pos curPos, peekPos token.Pos
fset *token.FileSet fset *token.FileSet
curToken, peekToken token.Token curToken, peekToken token.Token
curValue, peekValue string curValue, peekValue string
buf string buf string
params map[string]ast.Expr
} }
// newTokenizer initializes a new tokenizer, positioned at the first token in // newTokenizer initializes a new tokenizer, positioned at the first token in
// the string. // the string.
func newTokenizer(start token.Pos, fset *token.FileSet, buf string, f *cgoFile) *tokenizer { func newTokenizer(start token.Pos, fset *token.FileSet, buf string) *tokenizer {
t := &tokenizer{ t := &tokenizer{
f: f,
peekPos: start, peekPos: start,
fset: fset, fset: fset,
buf: buf, buf: buf,
peekToken: token.ILLEGAL, peekToken: token.ILLEGAL,
params: make(map[string]ast.Expr),
} }
// Parse the first two tokens (cur and peek). // Parse the first two tokens (cur and peek).
t.Next() t.Next()
@@ -360,7 +230,7 @@ func (t *tokenizer) Next() {
t.peekValue = t.buf[:2] t.peekValue = t.buf[:2]
t.buf = t.buf[2:] t.buf = t.buf[2:]
return return
case c == '(' || c == ')' || c == ',' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '&' || c == '|' || c == '^': case c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '&' || c == '|' || c == '^':
// Single-character tokens. // Single-character tokens.
// TODO: ++ (increment) and -- (decrement) operators. // TODO: ++ (increment) and -- (decrement) operators.
switch c { switch c {
@@ -368,8 +238,6 @@ func (t *tokenizer) Next() {
t.peekToken = token.LPAREN t.peekToken = token.LPAREN
case ')': case ')':
t.peekToken = token.RPAREN t.peekToken = token.RPAREN
case ',':
t.peekToken = token.COMMA
case '+': case '+':
t.peekToken = token.ADD t.peekToken = token.ADD
case '-': case '-':
+1 -1
View File
@@ -59,7 +59,7 @@ func TestParseConst(t *testing.T) {
} { } {
fset := token.NewFileSet() fset := token.NewFileSet()
startPos := fset.AddFile("", -1, 1000).Pos(0) startPos := fset.AddFile("", -1, 1000).Pos(0)
expr, err := parseConst(startPos, fset, tc.C, nil, token.NoPos, nil) expr, err := parseConst(startPos, fset, tc.C)
s := "<invalid>" s := "<invalid>"
if err != nil { if err != nil {
if !strings.HasPrefix(tc.Go, "error: ") { if !strings.HasPrefix(tc.Go, "error: ") {
+39 -59
View File
@@ -63,7 +63,6 @@ long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c); CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c); unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c);
unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c); unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c);
unsigned tinygo_clang_Cursor_isMacroFunctionLike(GoCXCursor c);
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data); int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data); int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
@@ -371,8 +370,45 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
gen.Specs = append(gen.Specs, valueSpec) gen.Specs = append(gen.Specs, valueSpec)
return gen, nil return gen, nil
case C.CXCursor_MacroDefinition: case C.CXCursor_MacroDefinition:
tokenPos, value := f.getMacro(c) // Extract tokens from the Clang tokenizer.
expr, scannerError := parseConst(tokenPos, f.fset, value, nil, token.NoPos, f) // See: https://stackoverflow.com/a/19074846/559350
sourceRange := C.tinygo_clang_getCursorExtent(c)
tu := C.tinygo_clang_Cursor_getTranslationUnit(c)
var rawTokens *C.CXToken
var numTokens C.unsigned
C.clang_tokenize(tu, sourceRange, &rawTokens, &numTokens)
tokens := unsafe.Slice(rawTokens, numTokens)
// Convert this range of tokens back to source text.
// Ugly, but it works well enough.
sourceBuf := &bytes.Buffer{}
var startOffset int
for i, token := range tokens {
spelling := getString(C.clang_getTokenSpelling(tu, token))
location := C.clang_getTokenLocation(tu, token)
var tokenOffset C.unsigned
C.clang_getExpansionLocation(location, nil, nil, nil, &tokenOffset)
if i == 0 {
// The first token is the macro name itself.
// Skip it (after using its location).
startOffset = int(tokenOffset) + len(name)
} else {
// Later tokens are the macro contents.
for int(tokenOffset) > (startOffset + sourceBuf.Len()) {
// Pad the source text with whitespace (that must have been
// present in the original source as well).
sourceBuf.WriteByte(' ')
}
sourceBuf.WriteString(spelling)
}
}
C.clang_disposeTokens(tu, rawTokens, numTokens)
value := sourceBuf.String()
// Try to convert this #define into a Go constant expression.
tokenPos := token.NoPos
if pos != token.NoPos {
tokenPos = pos + token.Pos(len(name))
}
expr, scannerError := parseConst(tokenPos, f.fset, value)
if scannerError != nil { if scannerError != nil {
f.errors = append(f.errors, *scannerError) f.errors = append(f.errors, *scannerError)
return nil, nil return nil, nil
@@ -452,62 +488,6 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
} }
} }
// Return whether this is a macro that's also function-like, like this:
//
// #define add(a, b) (a+b)
func (f *cgoFile) isFunctionLikeMacro(c clangCursor) bool {
if C.tinygo_clang_getCursorKind(c) != C.CXCursor_MacroDefinition {
return false
}
return C.tinygo_clang_Cursor_isMacroFunctionLike(c) != 0
}
// Get the macro value: the position in the source file and the string value of
// the macro.
func (f *cgoFile) getMacro(c clangCursor) (pos token.Pos, value string) {
// Extract tokens from the Clang tokenizer.
// See: https://stackoverflow.com/a/19074846/559350
sourceRange := C.tinygo_clang_getCursorExtent(c)
tu := C.tinygo_clang_Cursor_getTranslationUnit(c)
var rawTokens *C.CXToken
var numTokens C.unsigned
C.clang_tokenize(tu, sourceRange, &rawTokens, &numTokens)
tokens := unsafe.Slice(rawTokens, numTokens)
defer C.clang_disposeTokens(tu, rawTokens, numTokens)
// Convert this range of tokens back to source text.
// Ugly, but it works well enough.
sourceBuf := &bytes.Buffer{}
var startOffset int
for i, token := range tokens {
spelling := getString(C.clang_getTokenSpelling(tu, token))
location := C.clang_getTokenLocation(tu, token)
var tokenOffset C.unsigned
C.clang_getExpansionLocation(location, nil, nil, nil, &tokenOffset)
if i == 0 {
// The first token is the macro name itself.
// Skip it (after using its location).
startOffset = int(tokenOffset)
} else {
// Later tokens are the macro contents.
for int(tokenOffset) > (startOffset + sourceBuf.Len()) {
// Pad the source text with whitespace (that must have been
// present in the original source as well).
sourceBuf.WriteByte(' ')
}
sourceBuf.WriteString(spelling)
}
}
value = sourceBuf.String()
// Obtain the position of this token. This is the position of the first
// character in the 'value' string and is used to report errors at the
// correct location in the source file.
pos = f.getCursorPosition(c)
return
}
func getString(clangString C.CXString) (s string) { func getString(clangString C.CXString) (s string) {
rawString := C.clang_getCString(clangString) rawString := C.clang_getCString(clangString)
s = C.GoString(rawString) s = C.GoString(rawString)
-4
View File
@@ -84,7 +84,3 @@ unsigned tinygo_clang_Cursor_isAnonymous(CXCursor c) {
unsigned tinygo_clang_Cursor_isBitField(CXCursor c) { unsigned tinygo_clang_Cursor_isBitField(CXCursor c) {
return clang_Cursor_isBitField(c); return clang_Cursor_isBitField(c);
} }
unsigned tinygo_clang_Cursor_isMacroFunctionLike(CXCursor c) {
return clang_Cursor_isMacroFunctionLike(c);
}
-7
View File
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
-16
View File
@@ -3,26 +3,10 @@ package main
/* /*
#define foo 3 #define foo 3
#define bar foo #define bar foo
#define unreferenced 4
#define referenced unreferenced
#define fnlike() 5
#define fnlike_val fnlike()
#define square(n) (n*n)
#define square_val square(20)
#define add(a, b) (a + b)
#define add_val add(3, 5)
*/ */
import "C" import "C"
const ( const (
Foo = C.foo Foo = C.foo
Bar = C.bar Bar = C.bar
Baz = C.referenced
fnlike = C.fnlike_val
square = C.square_val
add = C.add_val
) )
-12
View File
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
@@ -47,8 +40,3 @@ type (
const C.foo = 3 const C.foo = 3
const C.bar = C.foo const C.bar = C.foo
const C.unreferenced = 4
const C.referenced = C.unreferenced
const C.fnlike_val = 5
const C.square_val = (20 * 20)
const C.add_val = (3 + 5)
-8
View File
@@ -26,11 +26,6 @@ import "C"
// #warning another warning // #warning another warning
import "C" import "C"
// #define add(a, b) (a+b)
// #define add_toomuch add(1, 2, 3)
// #define add_toolittle add(1)
import "C"
// Make sure that errors for the following lines won't change with future // Make sure that errors for the following lines won't change with future
// additions to the CGo preamble. // additions to the CGo preamble.
// //
@@ -56,7 +51,4 @@ var (
// constants passed by a command line parameter // constants passed by a command line parameter
_ = C.SOME_PARAM_CONST_invalid _ = C.SOME_PARAM_CONST_invalid
_ = C.SOME_PARAM_CONST_valid _ = C.SOME_PARAM_CONST_valid
_ = C.add_toomuch
_ = C.add_toolittle
) )
-11
View File
@@ -7,8 +7,6 @@
// testdata/errors.go:16:33: unexpected token ), expected end of expression // testdata/errors.go:16:33: unexpected token ), expected end of expression
// testdata/errors.go:17:34: unexpected token ), expected end of expression // testdata/errors.go:17:34: unexpected token ), expected end of expression
// -: unexpected token INT, expected end of expression // -: unexpected token INT, expected end of expression
// testdata/errors.go:30:35: unexpected number of parameters: expected 2, got 3
// testdata/errors.go:31:31: unexpected number of parameters: expected 2, got 1
// 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 C.char value in variable declaration (overflows)
@@ -19,8 +17,6 @@
// testdata/errors.go:114: undefined: C.SOME_CONST_b // testdata/errors.go:114: undefined: C.SOME_CONST_b
// testdata/errors.go:116: undefined: C.SOME_CONST_startspace // testdata/errors.go:116: undefined: C.SOME_CONST_startspace
// testdata/errors.go:119: undefined: C.SOME_PARAM_CONST_invalid // testdata/errors.go:119: undefined: C.SOME_PARAM_CONST_invalid
// testdata/errors.go:122: undefined: C.add_toomuch
// testdata/errors.go:123: undefined: C.add_toolittle
package main package main
@@ -48,13 +44,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
-7
View File
@@ -29,13 +29,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
-7
View File
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
-7
View File
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
//go:linkname C.__CBytes runtime.cgo_CBytes
func C.__CBytes([]byte) unsafe.Pointer
func C.CBytes(b []byte) unsafe.Pointer {
return C.__CBytes(b)
}
type ( type (
C.char uint8 C.char uint8
C.schar int8 C.schar int8
+5 -37
View File
@@ -33,17 +33,6 @@ func (c *Config) CPU() string {
return c.Target.CPU return c.Target.CPU
} }
// The current build mode (like the `-buildmode` command line flag).
func (c *Config) BuildMode() string {
if c.Options.BuildMode != "" {
return c.Options.BuildMode
}
if c.Target.BuildMode != "" {
return c.Target.BuildMode
}
return "default"
}
// Features returns a list of features this CPU supports. For example, for a // Features returns a list of features this CPU supports. For example, for a
// RISC-V processor, that could be "+a,+c,+m". For many targets, an empty list // RISC-V processor, that could be "+a,+c,+m". For many targets, an empty list
// will be returned. // will be returned.
@@ -71,7 +60,7 @@ func (c *Config) GOOS() string {
} }
// GOARCH returns the GOARCH of the target. This might not always be the actual // GOARCH returns the GOARCH of the target. This might not always be the actual
// architecture: for example, the AVR target is not supported by the Go standard // archtecture: for example, the AVR target is not supported by the Go standard
// library so such targets will usually pretend to be linux/arm. // library so such targets will usually pretend to be linux/arm.
func (c *Config) GOARCH() string { func (c *Config) GOARCH() string {
return c.Target.GOARCH return c.Target.GOARCH
@@ -83,19 +72,12 @@ func (c *Config) GOARM() string {
return c.Options.GOARM return c.Options.GOARM
} }
// GOMIPS will return the GOMIPS environment variable given to the compiler when
// building a program.
func (c *Config) GOMIPS() string {
return c.Options.GOMIPS
}
// BuildTags returns the complete list of build tags used during this build. // BuildTags returns the complete list of build tags used during this build.
func (c *Config) BuildTags() []string { func (c *Config) BuildTags() []string {
tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race) tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race)
tags = append(tags, []string{ tags = append(tags, []string{
"tinygo", // that's the compiler "tinygo", // that's the compiler
"purego", // to get various crypto packages to work "purego", // to get various crypto packages to work
"osusergo", // to get os/user to work
"math_big_pure_go", // to get math/big to work "math_big_pure_go", // to get math/big to work
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package "gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
"serial." + c.Serial()}...) // used inside the machine package "serial." + c.Serial()}...) // used inside the machine package
@@ -225,13 +207,10 @@ func (c *Config) RP2040BootPatch() bool {
return false return false
} }
// Return a canonicalized architecture name, so we don't have to deal with arm* // MuslArchitecture returns the architecture name as used in musl libc. It is
// vs thumb* vs arm64. // usually the same as the first part of the LLVM triple, but not always.
func CanonicalArchName(triple string) string { func MuslArchitecture(triple string) string {
arch := strings.Split(triple, "-")[0] arch := strings.Split(triple, "-")[0]
if arch == "arm64" {
return "aarch64"
}
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") { if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
return "arm" return "arm"
} }
@@ -241,12 +220,6 @@ func CanonicalArchName(triple string) string {
return arch return arch
} }
// MuslArchitecture returns the architecture name as used in musl libc. It is
// usually the same as the first part of the LLVM triple, but not always.
func MuslArchitecture(triple string) string {
return CanonicalArchName(triple)
}
// LibcPath returns the path to the libc directory. The libc path will be either // LibcPath returns the path to the libc directory. The libc path will be either
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache // a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built). // directory (which might not yet be built).
@@ -258,9 +231,6 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
if c.ABI() != "" { if c.ABI() != "" {
archname += "-" + c.ABI() archname += "-" + c.ABI()
} }
if c.Target.SoftFloat {
archname += "-softfloat"
}
// Try to load a precompiled library. // Try to load a precompiled library.
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name) precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)
@@ -406,8 +376,6 @@ func (c *Config) LDFlags() []string {
if c.Target.LinkerScript != "" { if c.Target.LinkerScript != "" {
ldflags = append(ldflags, "-T", c.Target.LinkerScript) ldflags = append(ldflags, "-T", c.Target.LinkerScript)
} }
ldflags = append(ldflags, c.Options.ExtLDFlags...)
return ldflags return ldflags
} }
@@ -475,7 +443,7 @@ func (c *Config) BinaryFormat(ext string) string {
// Programmer returns the flash method and OpenOCD interface name given a // Programmer returns the flash method and OpenOCD interface name given a
// particular configuration. It may either be all configured in the target JSON // particular configuration. It may either be all configured in the target JSON
// file or be modified using the -programmer command-line option. // file or be modified using the -programmmer command-line option.
func (c *Config) Programmer() (method, openocdInterface string) { func (c *Config) Programmer() (method, openocdInterface string) {
switch c.Options.Programmer { switch c.Options.Programmer {
case "": case "":
-12
View File
@@ -8,7 +8,6 @@ import (
) )
var ( var (
validBuildModeOptions = []string{"default", "c-shared"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"} validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"} validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb", "rtt"} validSerialOptions = []string{"none", "uart", "usb", "rtt"}
@@ -24,10 +23,8 @@ type Options struct {
GOOS string // environment variable GOOS string // environment variable
GOARCH string // environment variable GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm) GOARM string // environment variable (only used with GOARCH=arm)
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
Directory string // working dir, leave it unset to use the current working dir Directory string // working dir, leave it unset to use the current working dir
Target string Target string
BuildMode string // -buildmode flag
Opt string Opt string
GC string GC string
PanicStrategy string PanicStrategy string
@@ -58,19 +55,10 @@ type Options struct {
Timeout time.Duration Timeout time.Duration
WITPackage string // pass through to wasm-tools component embed invocation WITPackage string // pass through to wasm-tools component embed invocation
WITWorld string // pass through to wasm-tools component embed -w option WITWorld string // pass through to wasm-tools component embed -w option
ExtLDFlags []string
} }
// 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.
func (o *Options) Verify() error { func (o *Options) Verify() error {
if o.BuildMode != "" {
valid := isInArray(validBuildModeOptions, o.BuildMode)
if !valid {
return fmt.Errorf(`invalid buildmode option '%s': valid values are %s`,
o.BuildMode,
strings.Join(validBuildModeOptions, ", "))
}
}
if o.GC != "" { if o.GC != "" {
valid := isInArray(validGCOptions, o.GC) valid := isInArray(validGCOptions, o.GC)
if !valid { if !valid {
+97 -160
View File
@@ -30,9 +30,7 @@ type TargetSpec struct {
Features string `json:"features,omitempty"` Features string `json:"features,omitempty"`
GOOS string `json:"goos,omitempty"` GOOS string `json:"goos,omitempty"`
GOARCH string `json:"goarch,omitempty"` GOARCH string `json:"goarch,omitempty"`
SoftFloat bool // used for non-baremetal systems (GOMIPS=softfloat etc)
BuildTags []string `json:"build-tags,omitempty"` BuildTags []string `json:"build-tags,omitempty"`
BuildMode string `json:"buildmode,omitempty"` // default build mode (if nothing specified)
GC string `json:"gc,omitempty"` GC string `json:"gc,omitempty"`
Scheduler string `json:"scheduler,omitempty"` Scheduler string `json:"scheduler,omitempty"`
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none) Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
@@ -88,10 +86,6 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
if src.Uint() != 0 { if src.Uint() != 0 {
dst.Set(src) dst.Set(src)
} }
case reflect.Bool:
if src.Bool() {
dst.Set(src)
}
case reflect.Ptr: // for pointers, copy if not nil case reflect.Ptr: // for pointers, copy if not nil
if !src.IsNil() { if !src.IsNil() {
dst.Set(src) dst.Set(src)
@@ -178,7 +172,63 @@ func (spec *TargetSpec) resolveInherits() error {
// Load a target specification. // Load a target specification.
func LoadTarget(options *Options) (*TargetSpec, error) { func LoadTarget(options *Options) (*TargetSpec, error) {
if options.Target == "" { if options.Target == "" {
return defaultTarget(options) // Configure based on GOOS/GOARCH environment variables (falling back to
// runtime.GOOS/runtime.GOARCH), and generate a LLVM target based on it.
var llvmarch string
switch options.GOARCH {
case "386":
llvmarch = "i386"
case "amd64":
llvmarch = "x86_64"
case "arm64":
llvmarch = "aarch64"
case "arm":
switch options.GOARM {
case "5":
llvmarch = "armv5"
case "6":
llvmarch = "armv6"
case "7":
llvmarch = "armv7"
default:
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
}
case "mips":
llvmarch = "mips"
case "mipsle":
llvmarch = "mipsel"
case "wasm":
llvmarch = "wasm32"
default:
llvmarch = options.GOARCH
}
llvmvendor := "unknown"
llvmos := options.GOOS
switch llvmos {
case "darwin":
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
// to iOS!
llvmos = "macosx10.12.0"
if llvmarch == "aarch64" {
// Looks like Apple prefers to call this architecture ARM64
// instead of AArch64.
llvmarch = "arm64"
llvmos = "macosx11.0.0"
}
llvmvendor = "apple"
case "wasip1":
llvmos = "wasi"
}
// Target triples (which actually have four components, but are called
// triples for historical reasons) have the form:
// arch-vendor-os-environment
target := llvmarch + "-" + llvmvendor + "-" + llvmos
if options.GOOS == "windows" {
target += "-gnu"
} else if options.GOARCH == "arm" {
target += "-gnueabihf"
}
return defaultTarget(options.GOOS, options.GOARCH, target)
} }
// See whether there is a target specification for this target (e.g. // See whether there is a target specification for this target (e.g.
@@ -239,13 +289,14 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
return maps, nil return maps, nil
} }
// Load a target from environment variables (which default to func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
// runtime.GOOS/runtime.GOARCH). // No target spec available. Use the default one, useful on most systems
func defaultTarget(options *Options) (*TargetSpec, error) { // with a regular OS.
spec := TargetSpec{ spec := TargetSpec{
GOOS: options.GOOS, Triple: triple,
GOARCH: options.GOARCH, GOOS: goos,
BuildTags: []string{options.GOOS, options.GOARCH}, GOARCH: goarch,
BuildTags: []string{goos, goarch},
GC: "precise", GC: "precise",
Scheduler: "tasks", Scheduler: "tasks",
Linker: "cc", Linker: "cc",
@@ -253,109 +304,38 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
GDB: []string{"gdb"}, GDB: []string{"gdb"},
PortReset: "false", PortReset: "false",
} }
switch goarch {
// Configure target based on GOARCH.
var llvmarch string
switch options.GOARCH {
case "386": case "386":
llvmarch = "i386"
spec.CPU = "pentium4" spec.CPU = "pentium4"
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "amd64": case "amd64":
llvmarch = "x86_64"
spec.CPU = "x86-64" spec.CPU = "x86-64"
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "arm": case "arm":
spec.CPU = "generic" spec.CPU = "generic"
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables") spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
subarch := strings.Split(options.GOARM, ",") switch strings.Split(triple, "-")[0] {
if len(subarch) > 2 { case "armv5":
return nil, fmt.Errorf("invalid GOARM=%s, must be of form <num>,[hardfloat|softfloat]", options.GOARM) 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"
} case "armv6":
archLevel := subarch[0] spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
var fpu string case "armv7":
if len(subarch) >= 2 { spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
fpu = subarch[1]
} else {
// Pick the default fpu value: softfloat for armv5 and hardfloat
// above that.
if archLevel == "5" {
fpu = "softfloat"
} else {
fpu = "hardfloat"
}
}
switch fpu {
case "softfloat":
spec.CFlags = append(spec.CFlags, "-msoft-float")
spec.SoftFloat = true
case "hardfloat":
// Hardware floating point support is the default everywhere except
// on ARMv5 where it needs to be enabled explicitly.
if archLevel == "5" {
spec.CFlags = append(spec.CFlags, "-mfpu=vfpv2")
}
default:
return nil, fmt.Errorf("invalid extension GOARM=%s, must be softfloat or hardfloat", options.GOARM)
}
switch archLevel {
case "5":
llvmarch = "armv5"
if spec.SoftFloat {
spec.Features = "+armv5t,+soft-float,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
} else {
spec.Features = "+armv5t,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
}
case "6":
llvmarch = "armv6"
if spec.SoftFloat {
spec.Features = "+armv6,+dsp,+soft-float,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
} else {
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
}
case "7":
llvmarch = "armv7"
if spec.SoftFloat {
spec.Features = "+armv7-a,+dsp,+soft-float,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
} else {
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
}
default:
return nil, fmt.Errorf("invalid GOARM=%s, must be of form <num>,[hardfloat|softfloat] where num is 5, 6, or 7", options.GOARM)
} }
case "arm64": case "arm64":
spec.CPU = "generic" spec.CPU = "generic"
llvmarch = "aarch64" if goos == "darwin" {
if options.GOOS == "darwin" {
spec.Features = "+fp-armv8,+neon" spec.Features = "+fp-armv8,+neon"
// Looks like Apple prefers to call this architecture ARM64 } else if goos == "windows" {
// instead of AArch64.
llvmarch = "arm64"
} else if options.GOOS == "windows" {
spec.Features = "+fp-armv8,+neon,-fmv" spec.Features = "+fp-armv8,+neon,-fmv"
} else { // linux } else { // linux
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics" spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
} }
case "mips", "mipsle": case "mips", "mipsle":
spec.CPU = "mips32" spec.CPU = "mips32r2"
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
spec.CFlags = append(spec.CFlags, "-fno-pic") spec.CFlags = append(spec.CFlags, "-fno-pic")
if options.GOARCH == "mips" {
llvmarch = "mips" // big endian
} else {
llvmarch = "mipsel" // little endian
}
switch options.GOMIPS {
case "hardfloat":
spec.Features = "+fpxx,+mips32,+nooddspreg,-noabicalls"
case "softfloat":
spec.SoftFloat = true
spec.Features = "+mips32,+soft-float,-noabicalls"
spec.CFlags = append(spec.CFlags, "-msoft-float")
default:
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
}
case "wasm": case "wasm":
llvmarch = "wasm32"
spec.CPU = "generic" spec.CPU = "generic"
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm") spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
@@ -364,41 +344,24 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
"-mnontrapping-fptoint", "-mnontrapping-fptoint",
"-msign-ext", "-msign-ext",
) )
default:
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
} }
if goos == "darwin" {
// Configure target based on GOOS.
llvmos := options.GOOS
llvmvendor := "unknown"
switch options.GOOS {
case "darwin":
platformVersion := "10.12.0"
if options.GOARCH == "arm64" {
platformVersion = "11.0.0" // first macosx platform with arm64 support
}
llvmvendor = "apple"
spec.Linker = "ld.lld" spec.Linker = "ld.lld"
spec.Libc = "darwin-libSystem" spec.Libc = "darwin-libSystem"
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to arch := strings.Split(triple, "-")[0]
// iOS! platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
llvmos = "macosx" + platformVersion
spec.LDFlags = append(spec.LDFlags, spec.LDFlags = append(spec.LDFlags,
"-flavor", "darwin", "-flavor", "darwin",
"-dead_strip", "-dead_strip",
"-arch", llvmarch, "-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion, "-platform_version", "macos", platformVersion, platformVersion,
) )
spec.ExtraFiles = append(spec.ExtraFiles, } else if goos == "linux" {
"src/runtime/os_darwin.c",
"src/runtime/runtime_unix.c",
"src/runtime/signal.c")
case "linux":
spec.Linker = "ld.lld" spec.Linker = "ld.lld"
spec.RTLib = "compiler-rt" spec.RTLib = "compiler-rt"
spec.Libc = "musl" spec.Libc = "musl"
spec.LDFlags = append(spec.LDFlags, "--gc-sections") spec.LDFlags = append(spec.LDFlags, "--gc-sections")
if options.GOARCH == "arm64" { if goarch == "arm64" {
// Disable outline atomics. For details, see: // Disable outline atomics. For details, see:
// https://cpufun.substack.com/p/atomics-in-aarch64 // https://cpufun.substack.com/p/atomics-in-aarch64
// A better way would be to fully support outline atomics, which // A better way would be to fully support outline atomics, which
@@ -412,10 +375,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
// proper threading. // proper threading.
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics") spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
} }
spec.ExtraFiles = append(spec.ExtraFiles, } else if goos == "windows" {
"src/runtime/runtime_unix.c",
"src/runtime/signal.c")
case "windows":
spec.Linker = "ld.lld" spec.Linker = "ld.lld"
spec.Libc = "mingw-w64" spec.Libc = "mingw-w64"
// Note: using a medium code model, low image base and no ASLR // Note: using a medium code model, low image base and no ASLR
@@ -424,7 +384,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
// normally present in Go (without explicitly opting in). // normally present in Go (without explicitly opting in).
// For more discussion: // For more discussion:
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1 // https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
switch options.GOARCH { switch goarch {
case "amd64": case "amd64":
spec.LDFlags = append(spec.LDFlags, spec.LDFlags = append(spec.LDFlags,
"-m", "i386pep", "-m", "i386pep",
@@ -441,7 +401,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
"--no-insert-timestamp", "--no-insert-timestamp",
"--no-dynamicbase", "--no-dynamicbase",
) )
case "wasip1": } else if goos == "wasip1" {
spec.GC = "" // use default GC spec.GC = "" // use default GC
spec.Scheduler = "asyncify" spec.Scheduler = "asyncify"
spec.Linker = "wasm-ld" spec.Linker = "wasm-ld"
@@ -452,55 +412,33 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
"--stack-first", "--stack-first",
"--no-demangle", "--no-demangle",
) )
spec.Emulator = "wasmtime run --dir={tmpDir}::/tmp {}" spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
spec.ExtraFiles = append(spec.ExtraFiles, spec.ExtraFiles = append(spec.ExtraFiles,
"src/runtime/asm_tinygowasm.S", "src/runtime/asm_tinygowasm.S",
"src/internal/task/task_asyncify_wasm.S", "src/internal/task/task_asyncify_wasm.S",
) )
llvmos = "wasi" } else {
default: spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
} }
if goarch != "wasm" {
// Target triples (which actually have four components, but are called
// triples for historical reasons) have the form:
// arch-vendor-os-environment
spec.Triple = llvmarch + "-" + llvmvendor + "-" + llvmos
if options.GOOS == "windows" {
spec.Triple += "-gnu"
} else if options.GOOS == "linux" {
// We use musl on Linux (not glibc) so we should use -musleabi* instead
// of -gnueabi*.
// The *hf suffix selects between soft/hard floating point ABI.
if spec.SoftFloat {
spec.Triple += "-musleabi"
} else {
spec.Triple += "-musleabihf"
}
}
// Add extra assembly files (needed for the scheduler etc).
if options.GOARCH != "wasm" {
suffix := "" suffix := ""
if options.GOOS == "windows" && options.GOARCH == "amd64" { if goos == "windows" && goarch == "amd64" {
// Windows uses a different calling convention on amd64 from other // Windows uses a different calling convention on amd64 from other
// operating systems so we need separate assembly files. // operating systems so we need separate assembly files.
suffix = "_windows" suffix = "_windows"
} }
asmGoarch := options.GOARCH asmGoarch := goarch
if options.GOARCH == "mips" || options.GOARCH == "mipsle" { if goarch == "mips" || goarch == "mipsle" {
asmGoarch = "mipsx" asmGoarch = "mipsx"
} }
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S") spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S")
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S") spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S")
} }
if goarch != runtime.GOARCH {
// Configure the emulator.
if options.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 options.GOOS == "linux" { if goos == "linux" {
switch options.GOARCH { switch goarch {
case "386": case "386":
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case. // amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
if runtime.GOARCH != "amd64" { if runtime.GOARCH != "amd64" {
@@ -519,12 +457,11 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
} }
} }
} }
if options.GOOS != runtime.GOOS { if goos != runtime.GOOS {
if options.GOOS == "windows" { if goos == "windows" {
spec.Emulator = "wine {}" spec.Emulator = "wine {}"
} }
} }
return &spec, nil return &spec, nil
} }
+1 -1
View File
@@ -99,7 +99,7 @@ func (b *builder) createUnsafeSliceStringCheck(name string, ptr, len llvm.Value,
// However, in practice, it is also necessary to check that the length is // However, in practice, it is also necessary to check that the length is
// not too big that a GEP wouldn't be possible without wrapping the pointer. // not too big that a GEP wouldn't be possible without wrapping the pointer.
// These two checks (non-negative and not too big) can be merged into one // These two checks (non-negative and not too big) can be merged into one
// using an unsigned greater than. // using an unsiged greater than.
// Make sure the len value is at least as big as a uintptr. // Make sure the len value is at least as big as a uintptr.
len = b.extendInteger(len, lenType, b.uintptrType) len = b.extendInteger(len, lenType, b.uintptrType)
-10
View File
@@ -15,16 +15,6 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true) oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
// Return the new value, not the original value returned by atomicrmw. // Return the new value, not the original value returned by atomicrmw.
return b.CreateAdd(oldVal, val, "") return b.CreateAdd(oldVal, val, "")
case "AndInt32", "AndInt64", "AndUint32", "AndUint64", "AndUintptr":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAnd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
return oldVal
case "OrInt32", "OrInt64", "OrUint32", "OrUint64", "OrUintptr":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpOr, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
return oldVal
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer": case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn)) ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn)) val := b.getValue(b.fn.Params[1], getPos(b.fn))
+6 -23
View File
@@ -17,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"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/go/types/typeutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
@@ -45,7 +44,6 @@ type Config struct {
ABI string ABI string
GOOS string GOOS string
GOARCH string GOARCH string
BuildMode string
CodeModel string CodeModel string
RelocationModel string RelocationModel string
SizeLevel int SizeLevel int
@@ -244,7 +242,7 @@ func NewTargetMachine(config *Config) (llvm.TargetMachine, error) {
} }
// Sizes returns a types.Sizes appropriate for the given target machine. It // Sizes returns a types.Sizes appropriate for the given target machine. It
// includes the correct int size and alignment as is necessary for the Go // includes the correct int size and aligment as is necessary for the Go
// typechecker. // typechecker.
func Sizes(machine llvm.TargetMachine) types.Sizes { func Sizes(machine llvm.TargetMachine) types.Sizes {
targetData := machine.CreateTargetData() targetData := machine.CreateTargetData()
@@ -1386,11 +1384,6 @@ func (b *builder) createFunction() {
b.llvmFn.SetLinkage(llvm.InternalLinkage) b.llvmFn.SetLinkage(llvm.InternalLinkage)
b.createFunction() b.createFunction()
} }
// Create wrapper function that can be called externally.
if b.info.wasmExport != "" {
b.createWasmExport()
}
} }
// posser is an interface that's implemented by both ssa.Value and // posser is an interface that's implemented by both ssa.Value and
@@ -1681,10 +1674,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
result = b.CreateSelect(cmp, result, arg, "") result = b.CreateSelect(cmp, result, arg, "")
} }
return result, nil return result, nil
case "panic":
// This is rare, but happens in "defer panic()".
b.createRuntimeInvoke("_panic", argValues, "")
return llvm.Value{}, nil
case "print", "println": case "print", "println":
for i, value := range argValues { for i, value := range argValues {
if i >= 1 && callName == "println" { if i >= 1 && callName == "println" {
@@ -1858,9 +1847,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
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") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"): case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
if b.GOOS != "darwin" { return b.createSyscall(instr)
return b.createSyscall(instr)
}
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"): case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
return b.createRawSyscallNoError(instr) return b.createRawSyscallNoError(instr)
case name == "runtime.supportsRecover": case name == "runtime.supportsRecover":
@@ -1870,18 +1857,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
} }
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
case name == "runtime.panicStrategy": case name == "runtime.panicStrategy":
// These constants are defined in src/runtime/panic.go.
panicStrategy := map[string]uint64{ panicStrategy := map[string]uint64{
"print": tinygo.PanicStrategyPrint, "print": 1, // panicStrategyPrint
"trap": tinygo.PanicStrategyTrap, "trap": 2, // panicStrategyTrap
}[b.Config.PanicStrategy] }[b.Config.PanicStrategy]
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
case name == "runtime/interrupt.New": case name == "runtime/interrupt.New":
return b.createInterruptGlobal(instr) return b.createInterruptGlobal(instr)
case name == "internal/abi.FuncPCABI0":
retval := b.createDarwinFuncPCABI0Call(instr)
if !retval.IsNil() {
return retval, nil
}
} }
calleeType, callee = b.getFunction(fn) calleeType, callee = b.getFunction(fn)
@@ -1980,7 +1963,7 @@ func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
return value return value
} else { } else {
// indicates a compiler bug // indicates a compiler bug
panic("SSA value not previously found in function: " + expr.String()) panic("local has not been parsed: " + expr.String())
} }
} }
} }
+1 -8
View File
@@ -16,7 +16,6 @@ package compiler
import ( import (
"go/types" "go/types"
"strconv" "strconv"
"strings"
"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"
@@ -199,13 +198,7 @@ jal 1f
addiu $$ra, 8 addiu $$ra, 8
sw $$ra, 4($$5) sw $$ra, 4($$5)
.set at` .set at`
constraints = "={$4},{$5},~{$1},~{$2},~{$3},~{$5},~{$6},~{$7},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$16},~{$17},~{$18},~{$19},~{$20},~{$21},~{$22},~{$23},~{$24},~{$25},~{$26},~{$27},~{$28},~{$29},~{$30},~{$31},~{memory}" constraints = "={$4},{$5},~{$1},~{$2},~{$3},~{$5},~{$6},~{$7},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$16},~{$17},~{$18},~{$19},~{$20},~{$21},~{$22},~{$23},~{$24},~{$25},~{$26},~{$27},~{$28},~{$29},~{$30},~{$31},~{$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}"
if !strings.Contains(b.Features, "+soft-float") {
// Using floating point registers together with GOMIPS=softfloat
// results in a crash: "This value type is not natively supported!"
// So only add them when using hardfloat.
constraints += ",~{$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}"
}
case "riscv32": case "riscv32":
asmString = ` asmString = `
la a2, 1f la a2, 1f
+1 -1
View File
@@ -78,7 +78,7 @@ func (b *builder) trackValue(value llvm.Value) {
} }
} }
// trackPointer creates a call to runtime.trackPointer, bitcasting the pointer // trackPointer creates a call to runtime.trackPointer, bitcasting the poitner
// first if needed. The input value must be of LLVM pointer type. // first if needed. The input value must be of LLVM pointer type.
func (b *builder) trackPointer(value llvm.Value) { func (b *builder) trackPointer(value llvm.Value) {
b.createRuntimeCall("trackPointer", []llvm.Value{value, b.stackChainAlloca}, "") b.createRuntimeCall("trackPointer", []llvm.Value{value, b.stackChainAlloca}, "")
+51 -286
View File
@@ -7,14 +7,43 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"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"
) )
// createGo emits code to start a new goroutine. // createGo emits code to start a new goroutine.
func (b *builder) createGo(instr *ssa.Go) { func (b *builder) createGo(instr *ssa.Go) {
if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok { // Get all function parameters to pass to the goroutine.
var params []llvm.Value
for _, param := range instr.Call.Args {
params = append(params, b.getValue(param, getPos(instr)))
}
var prefix string
var funcPtr llvm.Value
var funcType llvm.Type
hasContext := false
if callee := instr.Call.StaticCallee(); callee != nil {
// Static callee is known. This makes it easier to start a new
// goroutine.
var context llvm.Value
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
funcValue := b.getValue(value, getPos(instr))
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
}
if !context.IsNil() {
params = append(params, context) // context parameter
hasContext = true
}
funcType, funcPtr = b.getFunction(callee)
} else if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok {
// We cheat. None of the builtins do any long or blocking operation, so // We cheat. None of the builtins do any long or blocking operation, so
// we might as well run these builtins right away without the program // we might as well run these builtins right away without the program
// noticing the difference. // noticing the difference.
@@ -45,38 +74,6 @@ func (b *builder) createGo(instr *ssa.Go) {
} }
b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos()) b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos())
return return
}
// Get all function parameters to pass to the goroutine.
var params []llvm.Value
for _, param := range instr.Call.Args {
params = append(params, b.expandFormalParam(b.getValue(param, getPos(instr)))...)
}
var prefix string
var funcPtr llvm.Value
var funcType llvm.Type
hasContext := false
if callee := instr.Call.StaticCallee(); callee != nil {
// Static callee is known. This makes it easier to start a new
// goroutine.
var context llvm.Value
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
funcValue := b.getValue(value, getPos(instr))
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
}
if !context.IsNil() {
params = append(params, context) // context parameter
hasContext = true
}
funcType, funcPtr = b.getFunction(callee)
} else if instr.Call.IsInvoke() { } else if instr.Call.IsInvoke() {
// This is a method call on an interface value. // This is a method call on an interface value.
itf := b.getValue(instr.Call.Value, getPos(instr)) itf := b.getValue(instr.Call.Value, getPos(instr))
@@ -102,7 +99,7 @@ func (b *builder) createGo(instr *ssa.Go) {
paramBundle := b.emitPointerPack(params) paramBundle := b.emitPointerPack(params)
var stackSize llvm.Value var stackSize llvm.Value
callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, false, instr.Pos()) callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize { if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy // The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF // function that will be replaced with a load from a special ELF
@@ -122,147 +119,6 @@ func (b *builder) createGo(instr *ssa.Go) {
b.createCall(fnType, start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.dataPtrType)}, "") b.createCall(fnType, start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.dataPtrType)}, "")
} }
// Create an exported wrapper function for functions with the //go:wasmexport
// pragma. This wrapper function is quite complex when the scheduler is enabled:
// it needs to start a new goroutine each time the exported function is called.
func (b *builder) createWasmExport() {
pos := b.info.wasmExportPos
if b.info.exported {
// //export really shouldn't be used anymore when //go:wasmexport is
// available, because //go:wasmexport is much better defined.
b.addError(pos, "cannot use //export and //go:wasmexport at the same time")
return
}
const suffix = "#wasmexport"
// Declare the exported function.
paramTypes := b.llvmFnType.ParamTypes()
exportedFnType := llvm.FunctionType(b.llvmFnType.ReturnType(), paramTypes[:len(paramTypes)-1], false)
exportedFn := llvm.AddFunction(b.mod, b.fn.RelString(nil)+suffix, exportedFnType)
b.addStandardAttributes(exportedFn)
llvmutil.AppendToGlobal(b.mod, "llvm.used", exportedFn)
exportedFn.AddFunctionAttr(b.ctx.CreateStringAttribute("wasm-export-name", b.info.wasmExport))
// Create a builder for this wrapper function.
builder := newBuilder(b.compilerContext, b.ctx.NewBuilder(), b.fn)
defer builder.Dispose()
// Define this function as a separate function in DWARF
if b.Debug {
if b.fn.Syntax() != nil {
// Create debug info file if needed.
pos := b.program.Fset.Position(pos)
builder.difunc = builder.attachDebugInfoRaw(b.fn, exportedFn, suffix, pos.Filename, pos.Line)
}
builder.setDebugLocation(pos)
}
// Create a single basic block inside of it.
bb := llvm.AddBasicBlock(exportedFn, "entry")
builder.SetInsertPointAtEnd(bb)
// Insert an assertion to make sure this //go:wasmexport function is not
// called at a time when it is not allowed (for example, before the runtime
// is initialized).
builder.createRuntimeCall("wasmExportCheckRun", nil, "")
if b.Scheduler == "none" {
// When the scheduler has been disabled, this is really trivial: just
// call the function.
params := exportedFn.Params()
params = append(params, llvm.ConstNull(b.dataPtrType)) // context parameter
retval := builder.CreateCall(b.llvmFnType, b.llvmFn, params, "")
if b.fn.Signature.Results() == nil {
builder.CreateRetVoid()
} else {
builder.CreateRet(retval)
}
} else {
// The scheduler is enabled, so we need to start a new goroutine, wait
// for it to complete, and read the result value.
// Build a function that looks like this:
//
// func foo#wasmexport(param0, param1, ..., paramN) {
// var state *stateStruct
//
// // 'done' must be explicitly initialized ('state' is not zeroed)
// state.done = false
//
// // store the parameters in the state object
// state.param0 = param0
// state.param1 = param1
// ...
// state.paramN = paramN
//
// // create a goroutine and push it to the runqueue
// task.start(uintptr(gowrapper), &state)
//
// // run the scheduler
// runtime.wasmExportRun(&state.done)
//
// // if there is a return value, load it and return
// return state.result
// }
hasReturn := b.fn.Signature.Results() != nil
// Build the state struct type.
// It stores the function parameters, the 'done' flag, and reserves
// space for a return value if needed.
stateFields := exportedFnType.ParamTypes()
numParams := len(stateFields)
stateFields = append(stateFields, b.ctx.Int1Type()) // 'done' field
if hasReturn {
stateFields = append(stateFields, b.llvmFnType.ReturnType())
}
stateStruct := b.ctx.StructType(stateFields, false)
// Allocate the state struct on the stack.
statePtr := builder.CreateAlloca(stateStruct, "status")
// Initialize the 'done' field.
doneGEP := builder.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(numParams), false),
}, "done.gep")
builder.CreateStore(llvm.ConstNull(b.ctx.Int1Type()), doneGEP)
// Store all parameters in the state object.
for i, param := range exportedFn.Params() {
gep := builder.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}, "")
builder.CreateStore(param, gep)
}
// Create a new goroutine and add it to the runqueue.
wrapper := b.createGoroutineStartWrapper(b.llvmFnType, b.llvmFn, "", false, true, pos)
stackSize := llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
taskStartFnType, taskStartFn := builder.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
builder.createCall(taskStartFnType, taskStartFn, []llvm.Value{wrapper, statePtr, stackSize, llvm.Undef(b.dataPtrType)}, "")
// Run the scheduler.
builder.createRuntimeCall("wasmExportRun", []llvm.Value{doneGEP}, "")
// Read the return value (if any) and return to the caller of the
// //go:wasmexport function.
if hasReturn {
gep := builder.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(numParams)+1, false),
}, "")
retval := builder.CreateLoad(b.llvmFnType.ReturnType(), gep, "retval")
builder.CreateRet(retval)
} else {
builder.CreateRetVoid()
}
}
}
// 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:
// //
@@ -286,7 +142,7 @@ func (b *builder) createWasmExport() {
// to last parameter of the function) is used for this wrapper. If hasContext is // to last parameter of the function) is used for this wrapper. If hasContext is
// false, the parameter bundle is assumed to have no context parameter and undef // false, the parameter bundle is assumed to have no context parameter and undef
// is passed instead. // is passed instead.
func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.Value, prefix string, hasContext, isWasmExport bool, pos token.Pos) llvm.Value { func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.Value, prefix string, hasContext bool, pos token.Pos) llvm.Value {
var wrapper llvm.Value var wrapper llvm.Value
b := &builder{ b := &builder{
@@ -304,18 +160,14 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
if !fn.IsAFunction().IsNil() { if !fn.IsAFunction().IsNil() {
// See whether this wrapper has already been created. If so, return it. // See whether this wrapper has already been created. If so, return it.
name := fn.Name() name := fn.Name()
wrapperName := name + "$gowrapper" wrapper = c.mod.NamedFunction(name + "$gowrapper")
if isWasmExport {
wrapperName += "-wasmexport"
}
wrapper = c.mod.NamedFunction(wrapperName)
if !wrapper.IsNil() { if !wrapper.IsNil() {
return llvm.ConstPtrToInt(wrapper, c.uintptrType) return llvm.ConstPtrToInt(wrapper, c.uintptrType)
} }
// Create the wrapper. // Create the wrapper.
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false) wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false)
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapperType) wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
c.addStandardAttributes(wrapper) c.addStandardAttributes(wrapper)
wrapper.SetLinkage(llvm.LinkOnceODRLinkage) wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
wrapper.SetUnnamedAddr(true) wrapper.SetUnnamedAddr(true)
@@ -345,110 +197,23 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
} }
if !isWasmExport { // Create the list of params for the call.
// Regular 'go' instruction. paramTypes := fnType.ParamTypes()
if !hasContext {
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
}
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
if !hasContext {
params = append(params, llvm.Undef(c.dataPtrType)) // add dummy context parameter
}
// Create the list of params for the call. // Create the call.
paramTypes := fnType.ParamTypes() b.CreateCall(fnType, fn, params, "")
if !hasContext {
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
}
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes) if c.Scheduler == "asyncify" {
if !hasContext { b.CreateCall(deadlockType, deadlock, []llvm.Value{
params = append(params, llvm.Undef(c.dataPtrType)) // add dummy context parameter llvm.Undef(c.dataPtrType),
} }, "")
// Create the call.
b.CreateCall(fnType, fn, params, "")
if c.Scheduler == "asyncify" {
b.CreateCall(deadlockType, deadlock, []llvm.Value{
llvm.Undef(c.dataPtrType),
}, "")
}
} else {
// Goroutine started from a //go:wasmexport pragma.
// The function looks like this:
//
// func foo$gowrapper-wasmexport(state *stateStruct) {
// // load values
// param0 := state.params[0]
// param1 := state.params[1]
//
// // call wrapped functions
// result := foo(param0, param1, ...)
//
// // store result value (if there is any)
// state.result = result
//
// // finish exported function
// state.done = true
// runtime.wasmExportExit()
// }
//
// The state object here looks like:
//
// struct state {
// param0
// param1
// param* // etc
// done bool
// result returnType
// }
returnType := fnType.ReturnType()
hasReturn := returnType != b.ctx.VoidType()
statePtr := wrapper.Param(0)
// Create the state struct (it must match the type in createWasmExport).
stateFields := fnType.ParamTypes()
numParams := len(stateFields) - 1
stateFields = stateFields[:numParams:numParams] // strip 'context' parameter
stateFields = append(stateFields, c.ctx.Int1Type()) // 'done' bool
if hasReturn {
stateFields = append(stateFields, returnType)
}
stateStruct := b.ctx.StructType(stateFields, false)
// Extract parameters from the state object, and call the function
// that's being wrapped.
var callParams []llvm.Value
for i := 0; i < numParams; i++ {
gep := b.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}, "")
param := b.CreateLoad(stateFields[i], gep, "")
callParams = append(callParams, param)
}
callParams = append(callParams, llvm.ConstNull(c.dataPtrType)) // add 'context' parameter
result := b.CreateCall(fnType, fn, callParams, "")
// Store the return value back into the shared state.
// Unlike regular goroutines, these special //go:wasmexport
// goroutines can return a value.
if hasReturn {
gep := b.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), uint64(numParams)+1, false),
}, "result.ptr")
b.CreateStore(result, gep)
}
// Mark this function as having finished executing.
// This is important so the runtime knows the exported function
// didn't block.
doneGEP := b.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), uint64(numParams), false),
}, "done.gep")
b.CreateStore(llvm.ConstInt(b.ctx.Int1Type(), 1, false), doneGEP)
// Call back into the runtime. This will exit the goroutine, switch
// back to the scheduler, which will in turn return from the
// //go:wasmexport function.
b.createRuntimeCall("wasmExportExit", nil, "")
} }
} else { } else {
@@ -530,5 +295,5 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
} }
// Return a ptrtoint of the wrapper, not the function itself. // Return a ptrtoint of the wrapper, not the function itself.
return llvm.ConstPtrToInt(wrapper, c.uintptrType) return b.CreatePtrToInt(wrapper, c.uintptrType, "")
} }
+7 -5
View File
@@ -86,7 +86,7 @@ func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.
// extractValueFromInterface extract the value from an interface value // extractValueFromInterface extract the value from an interface value
// (runtime._interface) under the assumption that it is of the type given in // (runtime._interface) under the assumption that it is of the type given in
// llvmType. The behavior is undefined if the interface is nil or llvmType // llvmType. The behavior is undefied if the interface is nil or llvmType
// doesn't match the underlying type of the interface. // doesn't match the underlying type of the interface.
func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value { func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value {
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr") valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
@@ -225,6 +225,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
) )
case *types.Map: case *types.Map:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "extraFlags", types.Typ[types.Uint8]),
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
@@ -273,10 +274,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
metabyte |= 1 << 6 metabyte |= 1 << 6
} }
if hashmapIsBinaryKey(typ) {
metabyte |= 1 << 7
}
switch typ := typ.(type) { switch typ := typ.(type) {
case *types.Basic: case *types.Basic:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
@@ -333,7 +330,12 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
c.getTypeCode(types.NewSlice(typ.Elem())), // slicePtr c.getTypeCode(types.NewSlice(typ.Elem())), // slicePtr
} }
case *types.Map: case *types.Map:
var extraFlags uint8
if hashmapIsBinaryKey(typ.Key()) {
extraFlags |= 1 // extraFlagIsBinaryKey
}
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int8Type(), uint64(extraFlags), false),
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elem c.getTypeCode(typ.Elem()), // elem
-3
View File
@@ -41,8 +41,6 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
// Create a new global of type runtime/interrupt.handle. Globals of this // Create a new global of type runtime/interrupt.handle. Globals of this
// type are lowered in the interrupt lowering pass. // type are lowered in the interrupt lowering pass.
// It must have an alignment of 1, otherwise LLVM thinks a ptrtoint of the
// global has the lower bits unset.
globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type() globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type()
globalLLVMType := b.getLLVMType(globalType) globalLLVMType := b.getLLVMType(globalType)
globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10) globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10)
@@ -50,7 +48,6 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
global.SetVisibility(llvm.HiddenVisibility) global.SetVisibility(llvm.HiddenVisibility)
global.SetGlobalConstant(true) global.SetGlobalConstant(true)
global.SetUnnamedAddr(true) global.SetUnnamedAddr(true)
global.SetAlignment(1)
initializer := llvm.ConstNull(globalLLVMType) initializer := llvm.ConstNull(globalLLVMType)
initializer = b.CreateInsertValue(initializer, funcContext, 0, "") initializer = b.CreateInsertValue(initializer, funcContext, 0, "")
initializer = b.CreateInsertValue(initializer, funcPtr, 1, "") initializer = b.CreateInsertValue(initializer, funcPtr, 1, "")
+12 -3
View File
@@ -7,7 +7,6 @@ import (
"math/big" "math/big"
"strings" "strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -419,11 +418,21 @@ func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.In
} }
} }
// archFamily returns the architecture from the LLVM triple but with some // archFamily returns the archtecture from the LLVM triple but with some
// architecture names ("armv6", "thumbv7m", etc) merged into a single // architecture names ("armv6", "thumbv7m", etc) merged into a single
// architecture name ("arm"). // architecture name ("arm").
func (c *compilerContext) archFamily() string { func (c *compilerContext) archFamily() string {
return compileopts.CanonicalArchName(c.Triple) arch := strings.Split(c.Triple, "-")[0]
if strings.HasPrefix(arch, "arm64") {
return "aarch64"
}
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
return "arm"
}
if arch == "mipsel" {
return "mips"
}
return arch
} }
// isThumb returns whether we're in ARM or in Thumb mode. It panics if the // isThumb returns whether we're in ARM or in Thumb mode. It panics if the
+1 -12
View File
@@ -8,7 +8,6 @@
package llvmutil package llvmutil
import ( import (
"encoding/binary"
"strconv" "strconv"
"strings" "strings"
@@ -208,7 +207,7 @@ func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
used.SetLinkage(llvm.AppendingLinkage) used.SetLinkage(llvm.AppendingLinkage)
} }
// Version returns the LLVM major version. // Return the LLVM major version.
func Version() int { func Version() int {
majorStr := strings.Split(llvm.Version, ".")[0] majorStr := strings.Split(llvm.Version, ".")[0]
major, err := strconv.Atoi(majorStr) major, err := strconv.Atoi(majorStr)
@@ -217,13 +216,3 @@ func Version() int {
} }
return major return major
} }
// Return the byte order for the given target triple. Most targets are little
// endian, but for example MIPS can be big-endian.
func ByteOrder(target string) binary.ByteOrder {
if strings.HasPrefix(target, "mips-") {
return binary.BigEndian
} else {
return binary.LittleEndian
}
}
+12 -6
View File
@@ -6,11 +6,17 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"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) {
@@ -18,20 +24,20 @@ 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 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 = uint64(tinygo.HashmapAlgorithmString) 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 = uint64(tinygo.HashmapAlgorithmBinary) 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 = uint64(tinygo.HashmapAlgorithmInterface) alg = hashmapAlgorithmInterface
} }
keySize := b.targetData.TypeAllocSize(llvmKeyType) keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType) valueSize := b.targetData.TypeAllocSize(llvmValueType)
@@ -320,7 +326,7 @@ func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
if i < numFields-1 { if i < numFields-1 {
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1) nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
} else { } else {
// Last field? Next offset is the total size of the allocate struct. // Last field? Next offset is the total size of the allcoate struct.
nextOffset = b.targetData.TypeAllocSize(llvmStructType) nextOffset = b.targetData.TypeAllocSize(llvmStructType)
} }
+106 -187
View File
@@ -12,7 +12,6 @@ import (
"strings" "strings"
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
@@ -24,17 +23,15 @@ import (
// The linkName value contains a valid link name, even if //go:linkname is not // The linkName value contains a valid link name, even if //go:linkname is not
// present. // present.
type functionInfo struct { type functionInfo struct {
wasmModule string // go:wasm-module wasmModule string // go:wasm-module
wasmName string // wasm-export-name or wasm-import-name in the IR wasmName string // wasm-export-name or wasm-import-name in the IR
wasmExport string // go:wasmexport is defined (export is unset, this adds an exported wrapper) linkName string // go:linkname, go:export - the IR function name
wasmExportPos token.Pos // position of //go:wasmexport comment section string // go:section - object file section name
linkName string // go:linkname, go:export - the IR function name exported bool // go:export, CGo
section string // go:section - object file section name interrupt bool // go:interrupt
exported bool // go:export, CGo nobounds bool // go:nobounds
interrupt bool // go:interrupt variadic bool // go:variadic (CGo only)
nobounds bool // go:nobounds inline inlineType // go:inline
variadic bool // go:variadic (CGo only)
inline inlineType // go:inline
} }
type inlineType int type inlineType int
@@ -142,8 +139,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// On *nix systems, the "abort" functuion in libc is used to handle fatal panics. // On *nix systems, the "abort" functuion in libc is used to handle fatal panics.
// Mark it as noreturn so LLVM can optimize away code. // Mark it as noreturn so LLVM can optimize away code.
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0)) llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
case "internal/abi.NoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.alloc": case "runtime.alloc":
// Tell the optimizer that runtime.alloc is an allocator, meaning that it // Tell the optimizer that runtime.alloc is an allocator, meaning that it
// returns values that are never null and never alias to an existing value. // returns values that are never null and never alias to an existing value.
@@ -173,12 +168,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)) llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.stringFromBytes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.stringFromRunes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.trackPointer": case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a // This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer // portable way (see gc_stack_portable.go). Indicate to the optimizer
@@ -227,7 +216,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, 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" && fn.Synthetic != "range-over-func yield" { if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" {
irbuilder := c.ctx.NewBuilder() irbuilder := c.ctx.NewBuilder()
b := newBuilder(c, irbuilder, fn) b := newBuilder(c, irbuilder, fn)
b.createFunction() b.createFunction()
@@ -250,22 +239,8 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
// Pick the default linkName. // Pick the default linkName.
linkName: f.RelString(nil), linkName: f.RelString(nil),
} }
// Check for a few runtime functions that are treated specially.
if info.linkName == "runtime.wasmEntryReactor" && c.BuildMode == "c-shared" {
info.linkName = "_initialize"
info.wasmName = "_initialize"
info.exported = true
}
if info.linkName == "runtime.wasmEntryCommand" && c.BuildMode == "default" {
info.linkName = "_start"
info.wasmName = "_start"
info.exported = true
}
// Check for //go: pragmas, which may change the link name (among others). // Check for //go: pragmas, which may change the link name (among others).
c.parsePragmas(&info, f) c.parsePragmas(&info, f)
c.functionInfos[f] = info c.functionInfos[f] = info
return info return info
} }
@@ -273,164 +248,126 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
// parsePragmas is used by getFunctionInfo to parse function pragmas such as // parsePragmas is used by getFunctionInfo to parse function pragmas such as
// //export or //go:noinline. // //export or //go:noinline.
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) { func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
syntax := f.Syntax() if f.Syntax() == nil {
if f.Origin() != nil {
syntax = f.Origin().Syntax()
}
if syntax == nil {
return return
} }
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
// Read all pragmas of this function.
var pragmas []*ast.Comment
hasWasmExport := false
if decl, ok := syntax.(*ast.FuncDecl); ok && decl.Doc != nil {
for _, comment := range decl.Doc.List { for _, comment := range decl.Doc.List {
text := comment.Text text := comment.Text
if strings.HasPrefix(text, "//go:") || strings.HasPrefix(text, "//export ") { if strings.HasPrefix(text, "//export ") {
pragmas = append(pragmas, comment) // Rewrite '//export' to '//go:export' for compatibility with
if strings.HasPrefix(comment.Text, "//go:wasmexport ") { // gc.
hasWasmExport = true text = "//go:" + text[2:]
}
if !strings.HasPrefix(text, "//go:") {
continue
}
parts := strings.Fields(text)
switch parts[0] {
case "//go:export":
if len(parts) != 2 {
continue
} }
}
}
}
// Parse each pragma. info.linkName = parts[1]
for _, comment := range pragmas { info.wasmName = info.linkName
parts := strings.Fields(comment.Text) info.exported = true
switch parts[0] { case "//go:interrupt":
case "//export", "//go:export": if hasUnsafeImport(f.Pkg.Pkg) {
if len(parts) != 2 { info.interrupt = true
continue }
} case "//go:wasm-module":
if hasWasmExport { // Alternative comment for setting the import module.
// //go:wasmexport overrides //export. // This is deprecated, use //go:wasmimport instead.
continue if len(parts) != 2 {
} continue
}
info.linkName = parts[1] info.wasmModule = parts[1]
info.wasmName = info.linkName case "//go:wasmimport":
info.exported = true // Import a WebAssembly function, for example a WASI function.
case "//go:interrupt": // Original proposal: https://github.com/golang/go/issues/38248
if hasUnsafeImport(f.Pkg.Pkg) { // Allow globally: https://github.com/golang/go/issues/59149
info.interrupt = true if len(parts) != 3 {
} continue
case "//go:wasm-module": }
// Alternative comment for setting the import module. c.checkWasmImport(f, comment.Text)
// This is deprecated, use //go:wasmimport instead. info.exported = true
if len(parts) != 2 { info.wasmModule = parts[1]
continue info.wasmName = parts[2]
} case "//go:inline":
info.wasmModule = parts[1] info.inline = inlineHint
case "//go:wasmimport": case "//go:noinline":
// Import a WebAssembly function, for example a WASI function.
// Original proposal: https://github.com/golang/go/issues/38248
// Allow globally: https://github.com/golang/go/issues/59149
if len(parts) != 3 {
continue
}
if f.Blocks != nil {
// Defined functions cannot be exported.
c.addError(f.Pos(), "can only use //go:wasmimport on declarations")
continue
}
c.checkWasmImportExport(f, comment.Text)
info.exported = true
info.wasmModule = parts[1]
info.wasmName = parts[2]
case "//go:wasmexport":
if f.Blocks == nil {
c.addError(f.Pos(), "can only use //go:wasmexport on definitions")
continue
}
if len(parts) != 2 {
c.addError(f.Pos(), fmt.Sprintf("expected one parameter to //go:wasmimport, not %d", len(parts)-1))
continue
}
name := parts[1]
if name == "_start" || name == "_initialize" {
c.addError(f.Pos(), fmt.Sprintf("//go:wasmexport does not allow %#v", name))
continue
}
if c.BuildMode != "c-shared" && f.RelString(nil) == "main.main" {
c.addError(f.Pos(), fmt.Sprintf("//go:wasmexport does not allow main.main to be exported with -buildmode=%s", c.BuildMode))
continue
}
if c.archFamily() != "wasm32" {
c.addError(f.Pos(), "//go:wasmexport is only supported on wasm")
}
c.checkWasmImportExport(f, comment.Text)
info.wasmExport = name
info.wasmExportPos = comment.Slash
case "//go:inline":
info.inline = inlineHint
case "//go:noinline":
info.inline = inlineNone
case "//go:linkname":
if len(parts) != 3 || parts[1] != f.Name() {
continue
}
// Only enable go:linkname when the package imports "unsafe".
// This is a slightly looser requirement than what gc uses: gc
// requires the file to import "unsafe", not the package as a
// whole.
if hasUnsafeImport(f.Pkg.Pkg) {
info.linkName = parts[2]
}
case "//go:section":
// Only enable go:section when the package imports "unsafe".
// go:section also implies go:noinline since inlining could
// move the code to a different section than that requested.
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
info.section = parts[1]
info.inline = inlineNone info.inline = inlineNone
} case "//go:linkname":
case "//go:nobounds": if len(parts) != 3 || parts[1] != f.Name() {
// Skip bounds checking in this function. Useful for some continue
// runtime functions. }
// This is somewhat dangerous and thus only imported in packages // Only enable go:linkname when the package imports "unsafe".
// that import unsafe. // This is a slightly looser requirement than what gc uses: gc
if hasUnsafeImport(f.Pkg.Pkg) { // requires the file to import "unsafe", not the package as a
info.nobounds = true // whole.
} if hasUnsafeImport(f.Pkg.Pkg) {
case "//go:variadic": info.linkName = parts[2]
// The //go:variadic pragma is emitted by the CGo preprocessing }
// pass for C variadic functions. This includes both explicit case "//go:section":
// (with ...) and implicit (no parameters in signature) // Only enable go:section when the package imports "unsafe".
// functions. // go:section also implies go:noinline since inlining could
if strings.HasPrefix(f.Name(), "C.") { // move the code to a different section than that requested.
// This prefix cannot naturally be created, it must have if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
// been created as a result of CGo preprocessing. info.section = parts[1]
info.variadic = true info.inline = inlineNone
}
case "//go:nobounds":
// Skip bounds checking in this function. Useful for some
// runtime functions.
// This is somewhat dangerous and thus only imported in packages
// that import unsafe.
if hasUnsafeImport(f.Pkg.Pkg) {
info.nobounds = true
}
case "//go:variadic":
// The //go:variadic pragma is emitted by the CGo preprocessing
// pass for C variadic functions. This includes both explicit
// (with ...) and implicit (no parameters in signature)
// functions.
if strings.HasPrefix(f.Name(), "C.") {
// This prefix cannot naturally be created, it must have
// been created as a result of CGo preprocessing.
info.variadic = true
}
} }
} }
} }
} }
// Check whether this function can be used in //go:wasmimport or // Check whether this function cannot be used in //go:wasmimport. It will add an
// //go:wasmexport. It will add an error if this is not the case. // error if this is the case.
// //
// The list of allowed types is based on this proposal: // The list of allowed types is based on this proposal:
// https://github.com/golang/go/issues/59149 // https://github.com/golang/go/issues/59149
func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string) { func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" { if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
// The runtime is a special case. Allow all kinds of parameters // The runtime is a special case. Allow all kinds of parameters
// (importantly, including pointers). // (importantly, including pointers).
return return
} }
if f.Blocks != nil {
// Defined functions cannot be exported.
c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
return
}
if f.Signature.Results().Len() > 1 { if f.Signature.Results().Len() > 1 {
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma)) c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
} else if f.Signature.Results().Len() == 1 { } else if f.Signature.Results().Len() == 1 {
result := f.Signature.Results().At(0) result := f.Signature.Results().At(0)
if !c.isValidWasmType(result.Type(), siteResult) { if !isValidWasmType(result.Type(), siteResult) {
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String())) c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
} }
} }
for _, param := range f.Params { for _, param := range f.Params {
// Check whether the type is allowed. // Check whether the type is allowed.
// Only a very limited number of types can be mapped to WebAssembly. // Only a very limited number of types can be mapped to WebAssembly.
if !c.isValidWasmType(param.Type(), siteParam) { if !isValidWasmType(param.Type(), siteParam) {
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String())) c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
} }
} }
@@ -443,15 +380,13 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
// //
// This previously reflected the additional restrictions documented here: // This previously reflected the additional restrictions documented here:
// https://github.com/golang/go/issues/59149 // https://github.com/golang/go/issues/59149
func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool { func isValidWasmType(typ types.Type, site wasmSite) bool {
switch typ := typ.Underlying().(type) { switch typ := typ.Underlying().(type) {
case *types.Basic: case *types.Basic:
switch typ.Kind() { switch typ.Kind() {
case types.Bool: case types.Bool:
return true return true
case types.Int8, types.Uint8, types.Int16, types.Uint16: case types.Int, types.Uint, types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
return site == siteIndirect
case types.Int32, types.Uint32, types.Int64, types.Uint64:
return true return true
case types.Float32, types.Float64: case types.Float32, types.Float64:
return true return true
@@ -462,35 +397,19 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
return site == siteParam || site == siteIndirect return site == siteParam || site == siteIndirect
} }
case *types.Array: case *types.Array:
return site == siteIndirect && c.isValidWasmType(typ.Elem(), siteIndirect) return site == siteIndirect && isValidWasmType(typ.Elem(), siteIndirect)
case *types.Struct: case *types.Struct:
if site != siteIndirect { if site != siteIndirect {
return false return false
} }
// Structs with no fields do not need structs.HostLayout
if typ.NumFields() == 0 {
return true
}
hasHostLayout := true // default to true before detecting Go version
// (*types.Package).GoVersion added in go1.21
if gv, ok := any(c.pkg).(interface{ GoVersion() string }); ok {
if goenv.Compare(gv.GoVersion(), "go1.23") >= 0 {
hasHostLayout = false // package structs added in go1.23
}
}
for i := 0; i < typ.NumFields(); i++ { for i := 0; i < typ.NumFields(); i++ {
ftyp := typ.Field(i).Type() if !isValidWasmType(typ.Field(i).Type(), siteIndirect) {
if ftyp.String() == "structs.HostLayout" {
hasHostLayout = true
continue
}
if !c.isValidWasmType(ftyp, siteIndirect) {
return false return false
} }
} }
return hasHostLayout return true
case *types.Pointer: case *types.Pointer:
return c.isValidWasmType(typ.Elem(), siteIndirect) return isValidWasmType(typ.Elem(), siteIndirect)
} }
return false return false
} }
+1 -63
View File
@@ -5,7 +5,6 @@ package compiler
import ( import (
"strconv" "strconv"
"strings"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
@@ -146,7 +145,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
// Also useful: // Also useful:
// https://web.archive.org/web/20220529105937/https://www.linux-mips.org/wiki/Syscall // https://web.archive.org/web/20220529105937/https://www.linux-mips.org/wiki/Syscall
// The syscall number goes in r2, the result also in r2. // The syscall number goes in r2, the result also in r2.
// Register r7 is both an input parameter and an output parameter: if it // Register r7 is both an input paramter and an output parameter: if it
// is non-zero, the system call failed and r2 is the error code. // is non-zero, the system call failed and r2 is the error code.
// The code below implements the O32 syscall ABI, not the N32 ABI. It // The code below implements the O32 syscall ABI, not the N32 ABI. It
// could implement both at the same time if needed (like what appears to // could implement both at the same time if needed (like what appears to
@@ -330,64 +329,3 @@ func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, err
retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "") retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "")
return retval, nil return retval, nil
} }
// Lower a call to internal/abi.FuncPCABI0 on MacOS.
// This function is called like this:
//
// syscall(abi.FuncPCABI0(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
//
// So we'll want to return a function pointer (as uintptr) that points to the
// libc function. Specifically, we _don't_ want to point to the trampoline
// function (which is implemented in Go assembly which we can't read), but
// rather to the actually intended function. For this we're going to assume that
// all the functions follow a specific pattern: libc_<functionname>_trampoline.
//
// The return value is the function pointer as an uintptr, or a nil value if
// this isn't possible (and a regular call should be made as fallback).
func (b *builder) createDarwinFuncPCABI0Call(instr *ssa.CallCommon) llvm.Value {
if b.GOOS != "darwin" {
// This has only been tested on MacOS (and only seems to be used there).
return llvm.Value{}
}
// Check that it uses a function call like syscall.libc_*_trampoline
itf := instr.Args[0].(*ssa.MakeInterface)
calledFn := itf.X.(*ssa.Function)
if pkgName := calledFn.Pkg.Pkg.Path(); pkgName != "syscall" && pkgName != "internal/syscall/unix" {
return llvm.Value{}
}
if !strings.HasPrefix(calledFn.Name(), "libc_") || !strings.HasSuffix(calledFn.Name(), "_trampoline") {
return llvm.Value{}
}
// Extract the libc function name.
name := strings.TrimPrefix(strings.TrimSuffix(calledFn.Name(), "_trampoline"), "libc_")
if name == "open" {
// Special case: open() is a variadic function and can't be called like
// a regular function. Therefore, we need to use a wrapper implemented
// in C.
name = "syscall_libc_open"
}
if b.GOARCH == "amd64" {
if name == "fdopendir" || name == "readdir_r" {
// Hack to support amd64, which needs the $INODE64 suffix.
// This is also done in upstream Go:
// https://github.com/golang/go/commit/096ab3c21b88ccc7d411379d09fe6274e3159467
name += "$INODE64"
}
}
// Obtain the C function.
// Use a simple function (no parameters or return value) because all we need
// is the address of the function.
llvmFn := b.mod.NamedFunction(name)
if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(b.ctx.VoidType(), nil, false)
llvmFn = llvm.AddFunction(b.mod, name, llvmFnType)
}
// Cast the function pointer to a uintptr (because that's what
// abi.FuncPCABI0 returns).
return b.CreatePtrToInt(llvmFn, b.uintptrType, "")
}
+7 -37
View File
@@ -1,9 +1,6 @@
package main package main
import ( import "unsafe"
"structs"
"unsafe"
)
//go:wasmimport modulename empty //go:wasmimport modulename empty
func empty() func empty()
@@ -17,37 +14,31 @@ func implementation() {
type Uint uint32 type Uint uint32
type S struct { type S struct {
_ structs.HostLayout
a [4]uint32 a [4]uint32
b uintptr b uintptr
c int
d float32 d float32
e float64 e float64
} }
//go:wasmimport modulename validparam //go:wasmimport modulename validparam
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S, j *struct{}, k *[8]uint8) func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S)
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [4]uint32 // ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [4]uint32
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte // ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type struct{a int} // ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type struct{a int}
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type chan struct{} // ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type chan struct{}
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type func() // ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type func()
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type uint
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [8]int
// //
//go:wasmimport modulename invalidparam //go:wasmimport modulename invalidparam
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func(), f int, g uint, h [8]int) func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func())
// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{int}
// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{string}
//
//go:wasmimport modulename invalidparam_no_hostlayout
func invalidparam_no_hostlayout(a *struct{ int }, b *struct{ string })
//go:wasmimport modulename validreturn_int32 //go:wasmimport modulename validreturn_int32
func validreturn_int32() int32 func validreturn_int32() int32
//go:wasmimport modulename validreturn_int
func validreturn_int() int
//go:wasmimport modulename validreturn_ptr_int32 //go:wasmimport modulename validreturn_ptr_int32
func validreturn_ptr_int32() *int32 func validreturn_ptr_int32() *int32
@@ -57,12 +48,6 @@ func validreturn_ptr_string() *string
//go:wasmimport modulename validreturn_ptr_struct //go:wasmimport modulename validreturn_ptr_struct
func validreturn_ptr_struct() *S func validreturn_ptr_struct() *S
//go:wasmimport modulename validreturn_ptr_struct
func validreturn_ptr_empty_struct() *struct{}
//go:wasmimport modulename validreturn_ptr_array
func validreturn_ptr_array() *[8]uint8
//go:wasmimport modulename validreturn_unsafe_pointer //go:wasmimport modulename validreturn_unsafe_pointer
func validreturn_unsafe_pointer() unsafe.Pointer func validreturn_unsafe_pointer() unsafe.Pointer
@@ -71,26 +56,11 @@ func validreturn_unsafe_pointer() unsafe.Pointer
//go:wasmimport modulename manyreturns //go:wasmimport modulename manyreturns
func manyreturns() (int32, int32) func manyreturns() (int32, int32)
// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type int
//
//go:wasmimport modulename invalidreturn_int
func invalidreturn_int() int
// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type uint
//
//go:wasmimport modulename invalidreturn_int
func invalidreturn_uint() uint
// ERROR: //go:wasmimport modulename invalidreturn_func: unsupported result type func() // ERROR: //go:wasmimport modulename invalidreturn_func: unsupported result type func()
// //
//go:wasmimport modulename invalidreturn_func //go:wasmimport modulename invalidreturn_func
func invalidreturn_func() func() func invalidreturn_func() func()
// ERROR: //go:wasmimport modulename invalidreturn_pointer_array_int: unsupported result type *[8]int
//
//go:wasmimport modulename invalidreturn_pointer_array_int
func invalidreturn_pointer_array_int() *[8]int
// ERROR: //go:wasmimport modulename invalidreturn_slice_byte: unsupported result type []byte // ERROR: //go:wasmimport modulename invalidreturn_slice_byte: unsupported result type []byte
// //
//go:wasmimport modulename invalidreturn_slice_byte //go:wasmimport modulename invalidreturn_slice_byte
+1 -1
View File
@@ -22,7 +22,7 @@ target triple = "wasm32-unknown-wasi"
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " } @"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" } @"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4 @"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4 @"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
; Function Attrs: allockind("alloc,zeroed") allocsize(0) ; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
+7 -5
View File
@@ -3,6 +3,8 @@ source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" 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" target triple = "thumbv7m-unknown-unknown-eabi"
%runtime._string = type { ptr, i32 }
@"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
; Function Attrs: allockind("alloc,zeroed") allocsize(0) ; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -148,12 +150,12 @@ define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value,
entry: entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9 %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
store ptr %itf.value, ptr %0, align 4 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1 %1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2 %.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
store i32 4, ptr %2, align 4 store i32 4, ptr %.repack1, align 4
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3 %2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
ret void ret void
+7 -5
View File
@@ -3,6 +3,8 @@ source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 }
@"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
; Function Attrs: allockind("alloc,zeroed") allocsize(0) ; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -159,12 +161,12 @@ entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9 %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store ptr %itf.value, ptr %0, align 4 store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1 %1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4 store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2 %.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
store i32 4, ptr %2, align 4 store i32 4, ptr %.repack1, align 4
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3 %2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
store ptr %itf.typecode, ptr %3, align 4 store ptr %itf.typecode, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void ret void
} }
+5 -5
View File
@@ -6,14 +6,14 @@ target triple = "wasm32-unknown-wasi"
%runtime._interface = type { ptr, ptr } %runtime._interface = type { ptr, ptr }
%runtime._string = type { ptr, i32 } %runtime._string = type { ptr, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4 @"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 66, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4 @"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4 @"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4 @"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1 @"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4 @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4 @"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.typeid:basic:int" = external constant i8 @"reflect/types.typeid:basic:int" = external constant i8
-16
View File
@@ -48,22 +48,6 @@ func inlineFunc() {
func noinlineFunc() { func noinlineFunc() {
} }
type Int interface {
int8 | int16
}
// Same for generic functions (but the compiler may miss the pragma due to it
// being generic).
//
//go:noinline
func noinlineGenericFunc[T Int]() {
}
func useGeneric() {
// Make sure the generic function above is instantiated.
noinlineGenericFunc[int8]()
}
// This function should have the specified section. // This function should have the specified section.
// //
//go:section .special_function_section //go:section .special_function_section
-13
View File
@@ -48,19 +48,6 @@ entry:
ret void ret void
} }
; Function Attrs: nounwind
define hidden void @main.useGeneric(ptr %context) unnamed_addr #2 {
entry:
call void @"main.noinlineGenericFunc[int8]"(ptr undef)
ret void
}
; Function Attrs: noinline nounwind
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #5 {
entry:
ret void
}
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" { define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
entry: entry:
+2 -2
View File
@@ -43,7 +43,7 @@ func CreateDiagnostics(err error) ProgramDiagnostic {
if err == nil { if err == nil {
return nil return nil
} }
// Right now, the compiler will only show errors for the first package that // Right now, the compiler will only show errors for the first pacakge that
// fails to build. This is likely to change in the future. // fails to build. This is likely to change in the future.
return ProgramDiagnostic{ return ProgramDiagnostic{
createPackageDiagnostic(err), createPackageDiagnostic(err),
@@ -147,7 +147,7 @@ func createDiagnostics(err error) []Diagnostic {
// last package // last package
fmt.Fprintln(buf, "\timports", pkgPath+": "+err.Err.Error()) fmt.Fprintln(buf, "\timports", pkgPath+": "+err.Err.Error())
} else { } else {
// not the last package // not the last pacakge
fmt.Fprintln(buf, "\timports", pkgPath) fmt.Fprintln(buf, "\timports", pkgPath)
} }
} }
+22 -40
View File
@@ -7,6 +7,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"testing" "testing"
"time"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics" "github.com/tinygo-org/tinygo/diagnostics"
@@ -14,57 +15,38 @@ import (
// Test the error messages of the TinyGo compiler. // Test the error messages of the TinyGo compiler.
func TestErrors(t *testing.T) { func TestErrors(t *testing.T) {
// TODO: nicely formatted error messages for: for _, name := range []string{
// - duplicate symbols in ld.lld (currently only prints bitcode file) "cgo",
type errorTest struct { "compiler",
name string "interp",
target string "loader-importcycle",
} "loader-invaliddep",
for _, tc := range []errorTest{ "loader-invalidpackage",
{name: "cgo"}, "loader-nopackage",
{name: "compiler"}, "optimizer",
{name: "interp"}, "syntax",
{name: "invalidmain"}, "types",
{name: "invalidname"},
{name: "linker-flashoverflow", target: "cortex-m-qemu"},
{name: "linker-ramoverflow", target: "cortex-m-qemu"},
{name: "linker-undefined", target: "darwin/arm64"},
{name: "linker-undefined", target: "linux/amd64"},
//{name: "linker-undefined", target: "windows/amd64"}, // TODO: no source location
{name: "linker-undefined", target: "cortex-m-qemu"},
//{name: "linker-undefined", target: "wasip1"}, // TODO: no source location
{name: "loader-importcycle"},
{name: "loader-invaliddep"},
{name: "loader-invalidpackage"},
{name: "loader-nopackage"},
{name: "optimizer"},
{name: "syntax"},
{name: "types"},
} { } {
name := tc.name
if tc.target != "" {
name += "#" + tc.target
}
target := tc.target
if target == "" {
target = "wasip1"
}
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
options := optionsFromTarget(target, sema) testErrorMessages(t, "./testdata/errors/"+name+".go")
testErrorMessages(t, "./testdata/errors/"+tc.name+".go", &options)
}) })
} }
} }
func testErrorMessages(t *testing.T, filename string, options *compileopts.Options) { func testErrorMessages(t *testing.T, filename string) {
t.Parallel()
// Parse expected error messages. // Parse expected error messages.
expected := readErrorMessages(t, filename) expected := readErrorMessages(t, filename)
// Try to build a binary (this should fail with an error). // Try to build a binary (this should fail with an error).
tmpdir := t.TempDir() tmpdir := t.TempDir()
err := Build(filename, tmpdir+"/out", options) err := Build(filename, tmpdir+"/out", &compileopts.Options{
Target: "wasip1",
Semaphore: sema,
InterpTimeout: 180 * time.Second,
Debug: true,
VerifyIR: true,
Opt: "z",
})
if err == nil { if err == nil {
t.Fatal("expected to get a compiler error") t.Fatal("expected to get a compiler error")
} }
Generated
+4 -4
View File
@@ -20,16 +20,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1728500571, "lastModified": 1703068421,
"narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=", "narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0", "rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "id": "nixpkgs",
"ref": "nixos-24.05", "ref": "nixos-23.11",
"type": "indirect" "type": "indirect"
} }
}, },
+6 -6
View File
@@ -35,7 +35,7 @@
inputs = { inputs = {
# Use a recent stable release, but fix the version to make it reproducible. # Use a recent stable release, but fix the version to make it reproducible.
# This version should be updated from time to time. # This version should be updated from time to time.
nixpkgs.url = "nixpkgs/nixos-24.05"; nixpkgs.url = "nixpkgs/nixos-23.11";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = { self, nixpkgs, flake-utils }: outputs = { self, nixpkgs, flake-utils }:
@@ -49,11 +49,11 @@
buildInputs = [ buildInputs = [
# These dependencies are required for building tinygo (go install). # These dependencies are required for building tinygo (go install).
go go
llvmPackages_18.llvm llvmPackages_17.llvm
llvmPackages_18.libclang llvmPackages_17.libclang
# Additional dependencies needed at runtime, for building and/or # Additional dependencies needed at runtime, for building and/or
# flashing. # flashing.
llvmPackages_18.lld llvmPackages_17.lld
avrdude avrdude
binaryen binaryen
# Additional dependencies needed for on-chip debugging. # Additional dependencies needed for on-chip debugging.
@@ -68,7 +68,7 @@
# Without setting these explicitly, Homebrew versions might be used # Without setting these explicitly, Homebrew versions might be used
# or the default `ar` and `nm` tools might be used (which don't # or the default `ar` and `nm` tools might be used (which don't
# support wasi). # support wasi).
export CLANG="clang-18 -resource-dir ${llvmPackages_18.clang.cc.lib}/lib/clang/18" export CLANG="clang-17 -resource-dir ${llvmPackages_17.clang.cc.lib}/lib/clang/17"
export LLVM_AR=llvm-ar export LLVM_AR=llvm-ar
export LLVM_NM=llvm-nm export LLVM_NM=llvm-nm
@@ -77,7 +77,7 @@
export MD5SUM=md5sum export MD5SUM=md5sum
# Ugly hack to make the Clang resources directory available. # Ugly hack to make the Clang resources directory available.
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_18.clang.cc.lib}/lib/clang/18\" -tags=llvm18" export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_17.clang.cc.lib}/lib/clang/17\" -tags=llvm17"
''; '';
}; };
} }
+12 -2
View File
@@ -7,14 +7,15 @@ require (
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6 github.com/chromedp/chromedp v0.7.6
github.com/client9/misspell v0.3.4
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-tty v0.0.4 github.com/mattn/go-tty v0.0.4
github.com/mgechev/revive v1.3.7
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
github.com/tetratelabs/wazero v1.6.0
go.bug.st/serial v1.6.0 go.bug.st/serial v1.6.0
golang.org/x/net v0.26.0 golang.org/x/net v0.26.0
golang.org/x/sys v0.21.0 golang.org/x/sys v0.21.0
@@ -24,14 +25,23 @@ require (
) )
require ( require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect github.com/chromedp/sysutil v1.0.0 // indirect
github.com/creack/goselect v0.1.2 // indirect github.com/creack/goselect v0.1.2 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect github.com/gobwas/ws v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.8.4 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.11.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.16.0 // indirect
) )
+34 -2
View File
@@ -1,7 +1,11 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c h1:4T0Vj1UkGgcpkRrmn7SbokebnlfxJcMZPgWtOYACAAA= github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c h1:4T0Vj1UkGgcpkRrmn7SbokebnlfxJcMZPgWtOYACAAA=
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw= github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU= github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
@@ -9,9 +13,17 @@ github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo= github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
@@ -39,17 +51,35 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E= github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc= github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A= go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE= go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
@@ -73,6 +103,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 h1:bLsZXRUBavt++CJlMN7sppNziqu3LyamESLhFJcpqFQ= tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 h1:bLsZXRUBavt++CJlMN7sppNziqu3LyamESLhFJcpqFQ=
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+1 -11
View File
@@ -30,11 +30,8 @@ var Keys = []string{
} }
func init() { func init() {
switch Get("GOARCH") { if Get("GOARCH") == "arm" {
case "arm":
Keys = append(Keys, "GOARM") Keys = append(Keys, "GOARM")
case "mips", "mipsle":
Keys = append(Keys, "GOMIPS")
} }
} }
@@ -131,13 +128,6 @@ func Get(name string) string {
// difference between ARMv6 and ARMv7. ARMv6 binaries are much smaller, // difference between ARMv6 and ARMv7. ARMv6 binaries are much smaller,
// especially when floating point instructions are involved. // especially when floating point instructions are involved.
return "6" return "6"
case "GOMIPS":
gomips := os.Getenv("GOMIPS")
if gomips == "" {
// Default to hardfloat (this matches the Go toolchain).
gomips = "hardfloat"
}
return gomips
case "GOROOT": case "GOROOT":
readGoEnvVars() readGoEnvVars()
return goEnvVars.GOROOT return goEnvVars.GOROOT
+17 -65
View File
@@ -4,37 +4,29 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"runtime/debug"
"strings" "strings"
) )
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const version = "0.35.0-dev" const version = "0.33.0-dev"
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
GitSha1 string
)
// Return TinyGo version, either in the form 0.30.0 or as a development version // Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012). // (like 0.30.0-dev-abcd012).
func Version() string { func Version() string {
v := version v := version
if strings.HasSuffix(version, "-dev") { if strings.HasSuffix(version, "-dev") && GitSha1 != "" {
if hash := readGitHash(); hash != "" { v += "-" + GitSha1
v += "-" + hash
}
} }
return v return v
} }
func readGitHash() string {
if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
if setting.Key == "vcs.revision" {
return setting.Value[:8]
}
}
}
return ""
}
// GetGorootVersion returns the major and minor version for a given GOROOT path. // GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned. // If the goroot cannot be determined, (0, 0) is returned.
func GetGorootVersion() (major, minor int, err error) { func GetGorootVersion() (major, minor int, err error) {
@@ -42,67 +34,27 @@ func GetGorootVersion() (major, minor int, err error) {
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
major, minor, _, err = Parse(s)
return major, minor, err
}
// Parse parses the Go version (like "go1.3.2") in the parameter and return the if s == "" || s[:2] != "go" {
// major, minor, and patch version: 1, 3, and 2 in this example. return 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
// If there is an error, (0, 0, 0) and an error will be returned.
func Parse(version string) (major, minor, patch int, err error) {
if strings.HasPrefix(version, "devel ") {
version = strings.Split(strings.TrimPrefix(version, "devel "), version)[0]
}
if version == "" || version[:2] != "go" {
return 0, 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
} }
parts := strings.Split(version[2:], ".") parts := strings.Split(s[2:], ".")
if len(parts) < 2 { if len(parts) < 2 {
return 0, 0, 0, errors.New("could not parse Go version: version has less than two parts") return 0, 0, errors.New("could not parse Go version: version has less than two parts")
} }
// Ignore the errors, we don't really handle errors here anyway. // Ignore the errors, we don't really handle errors here anyway.
var trailing string var trailing string
n, err := fmt.Sscanf(version, "go%d.%d.%d%s", &major, &minor, &patch, &trailing) n, err := fmt.Sscanf(s, "go%d.%d%s", &major, &minor, &trailing)
if n == 2 { if n == 2 && err == io.EOF {
n, err = fmt.Sscanf(version, "go%d.%d%s", &major, &minor, &trailing)
}
if n >= 2 && err == io.EOF {
// Means there were no trailing characters (i.e., not an alpha/beta) // Means there were no trailing characters (i.e., not an alpha/beta)
err = nil err = nil
} }
if err != nil { if err != nil {
return 0, 0, 0, fmt.Errorf("failed to parse version: %s", err) return 0, 0, fmt.Errorf("failed to parse version: %s", err)
}
return major, minor, patch, nil
}
// Compare compares two Go version strings.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
// If either a or b is not a valid Go version, it is treated as "go0.0"
// and compared lexicographically.
// See [Parse] for more information.
func Compare(a, b string) int {
aMajor, aMinor, aPatch, _ := Parse(a)
bMajor, bMinor, bPatch, _ := Parse(b)
switch {
case aMajor < bMajor:
return -1
case aMajor > bMajor:
return +1
case aMinor < bMinor:
return -1
case aMinor > bMinor:
return +1
case aPatch < bPatch:
return -1
case aPatch > bPatch:
return +1
default:
return strings.Compare(a, b)
} }
return
} }
// GorootVersionString returns the version string as reported by the Go // GorootVersionString returns the version string as reported by the Go
-72
View File
@@ -1,72 +0,0 @@
package goenv
import "testing"
func TestParse(t *testing.T) {
tests := []struct {
v string
major int
minor int
patch int
wantErr bool
}{
{"", 0, 0, 0, true},
{"go", 0, 0, 0, true},
{"go1", 0, 0, 0, true},
{"go.0", 0, 0, 0, true},
{"go1.0", 1, 0, 0, false},
{"go1.1", 1, 1, 0, false},
{"go1.23", 1, 23, 0, false},
{"go1.23.5", 1, 23, 5, false},
{"go1.23.5-rc6", 1, 23, 5, false},
{"go2.0", 2, 0, 0, false},
{"go2.0.15", 2, 0, 15, false},
{"devel go1.24-f99f5da18f Thu Nov 14 22:29:26 2024 +0000 darwin/arm64", 1, 24, 0, false},
}
for _, tt := range tests {
t.Run(tt.v, func(t *testing.T) {
major, minor, patch, err := Parse(tt.v)
if err == nil && tt.wantErr {
t.Errorf("Parse(%q): expected err != nil", tt.v)
}
if err != nil && !tt.wantErr {
t.Errorf("Parse(%q): expected err == nil", tt.v)
}
if major != tt.major || minor != tt.minor || patch != tt.patch {
t.Errorf("Parse(%q): expected %d, %d, %d, nil; got %d, %d, %d, %v",
tt.v, tt.major, tt.minor, tt.patch, major, minor, patch, err)
}
})
}
}
func TestCompare(t *testing.T) {
tests := []struct {
a string
b string
want int
}{
{"", "", 0},
{"go0", "go0", 0},
{"go0", "go1", -1},
{"go1", "go0", 1},
{"go1", "go2", -1},
{"go2", "go1", 1},
{"go1.1", "go1.2", -1},
{"go1.2", "go1.1", 1},
{"go1.1.0", "go1.2.0", -1},
{"go1.2.0", "go1.1.0", 1},
{"go1.2.0", "go2.3.0", -1},
{"go1.23.2", "go1.23.10", -1},
{"go0.1.22", "go1.23.101", -1},
}
for _, tt := range tests {
t.Run(tt.a+" "+tt.b, func(t *testing.T) {
got := Compare(tt.a, tt.b)
if got != tt.want {
t.Errorf("Compare(%q, %q): expected %d; got %d",
tt.a, tt.b, tt.want, got)
}
})
}
}
-30
View File
@@ -1,30 +0,0 @@
// TODO: remove this (by merging it into the top-level go.mod)
// once the top level go.mod specifies a go new enough to make our version of misspell happy.
module tools
go 1.21
require (
github.com/golangci/misspell v0.6.0
github.com/mgechev/revive v1.3.9
)
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.11.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.23.0 // indirect
)
-56
View File
@@ -1,56 +0,0 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+2 -2
View File
@@ -5,9 +5,9 @@
package tools package tools
import ( import (
_ "github.com/golangci/misspell" _ "github.com/client9/misspell"
_ "github.com/mgechev/revive" _ "github.com/mgechev/revive"
) )
//go:generate go install github.com/golangci/misspell/cmd/misspell //go:generate go install github.com/client9/misspell/cmd/misspell
//go:generate go install github.com/mgechev/revive //go:generate go install github.com/mgechev/revive
+4 -10
View File
@@ -2,17 +2,11 @@ module github.com/tinygo-org/tinygo/internal/tools
go 1.22.4 go 1.22.4
require github.com/bytecodealliance/wasm-tools-go v0.3.1 require github.com/ydnar/wasm-tools-go v0.1.4
require ( require (
github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/urfave/cli/v3 v3.0.0-alpha9 // indirect
github.com/klauspost/compress v1.17.9 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect golang.org/x/mod v0.19.0 // indirect
github.com/regclient/regclient v0.7.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-alpha9.2 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.26.0 // indirect
) )
+14 -33
View File
@@ -1,44 +1,25 @@
github.com/bytecodealliance/wasm-tools-go v0.3.1 h1:9Q9PjSzkbiVmkUvZ7nYCfJ02mcQDBalxycA3s8g7kR4=
github.com/bytecodealliance/wasm-tools-go v0.3.1/go.mod h1:vNAQ8DAEp6xvvk+TUHah5DslLEa76f4H6e737OeaxuY=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/olareg/olareg v0.1.0 h1:1dXBOgPrig5N7zoXyIZVQqU0QBo6sD9pbL6UYjY75CA=
github.com/olareg/olareg v0.1.0/go.mod h1:RBuU7JW7SoIIxZKzLRhq8sVtQeAHzCAtRrXEBx2KlM4=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.7.1 h1:qEsJrTmZd98fZKjueAbrZCSNGU+ifnr6xjlSAs3WOPs=
github.com/regclient/regclient v0.7.1/go.mod h1:+w/BFtJuw0h0nzIw/z2+1FuA2/dVXBzDq4rYmziJpMc=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ydnar/wasm-tools-go v0.1.4 h1:+25WqBj0AhLx8OFvZvrs7bQO6L3WtQ7t6JzQEYsXQb8=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ydnar/wasm-tools-go v0.1.4/go.mod h1:lQfv2Tde3tRgZDSYriro0EmdSHzP1mrHPMmYNahSS/g=
github.com/urfave/cli/v3 v3.0.0-alpha9.2 h1:CL8llQj3dGRLVQQzHxS+ZYRLanOuhyK1fXgLKD+qV+Y= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
github.com/urfave/cli/v3 v3.0.0-alpha9.2/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+2 -2
View File
@@ -5,7 +5,7 @@
package tools package tools
import ( import (
_ "github.com/bytecodealliance/wasm-tools-go/cmd/wit-bindgen-go" _ "github.com/ydnar/wasm-tools-go/cmd/wit-bindgen-go"
) )
//go:generate go install github.com/bytecodealliance/wasm-tools-go/cmd/wit-bindgen-go //go:generate go install github.com/ydnar/wasm-tools-go/cmd/wit-bindgen-go
+1 -1
View File
@@ -28,7 +28,7 @@ All in all, this design provides several benefits:
it should be a whole lot faster for loops as it doesn't have to call into it should be a whole lot faster for loops as it doesn't have to call into
LLVM (via CGo) for every operation. LLVM (via CGo) for every operation.
As mentioned, this partial evaluator comes in three parts: a compiler, an As mentioned, this partial evaulator comes in three parts: a compiler, an
interpreter, and a memory manager. interpreter, and a memory manager.
## Compiler ## Compiler
+1 -5
View File
@@ -3,13 +3,11 @@
package interp package interp
import ( import (
"encoding/binary"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -26,7 +24,6 @@ type runner struct {
dataPtrType llvm.Type // often used type so created in advance dataPtrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
byteOrder binary.ByteOrder // big-endian or little-endian
debug bool // log debug messages debug bool // log debug messages
pkgName string // package name of the currently executing package pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions functionCache map[llvm.Value]*function // cache of compiled functions
@@ -41,7 +38,6 @@ func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
r := runner{ r := runner{
mod: mod, mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()), targetData: llvm.NewTargetData(mod.DataLayout()),
byteOrder: llvmutil.ByteOrder(mod.Target()),
debug: debug, debug: debug,
functionCache: make(map[llvm.Value]*function), functionCache: make(map[llvm.Value]*function),
objects: []object{{}}, objects: []object{{}},
@@ -56,7 +52,7 @@ func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
return &r return &r
} }
// Dispose deallocates all allocated LLVM resources. // Dispose deallocates all alloated LLVM resources.
func (r *runner) dispose() { func (r *runner) dispose() {
r.targetData.Dispose() r.targetData.Dispose()
r.targetData = llvm.TargetData{} r.targetData = llvm.TargetData{}
+49 -49
View File
@@ -173,7 +173,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
case 3: case 3:
// Conditional branch: [cond, thenBB, elseBB] // Conditional branch: [cond, thenBB, elseBB]
lastBB = currentBB lastBB = currentBB
switch operands[0].Uint(r) { switch operands[0].Uint() {
case 1: // true -> thenBB case 1: // true -> thenBB
currentBB = int(operands[1].(literalValue).value.(uint32)) currentBB = int(operands[1].(literalValue).value.(uint32))
case 0: // false -> elseBB case 0: // false -> elseBB
@@ -191,12 +191,12 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
case llvm.Switch: case llvm.Switch:
// Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...] // Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...]
value := operands[0].Uint(r) value := operands[0].Uint()
targetLabel := operands[1].Uint(r) // default label targetLabel := operands[1].Uint() // default label
// Do a lazy switch by iterating over all cases. // Do a lazy switch by iterating over all cases.
for i := 2; i < len(operands); i += 2 { for i := 2; i < len(operands); i += 2 {
if value == operands[i].Uint(r) { if value == operands[i].Uint() {
targetLabel = operands[i+1].Uint(r) targetLabel = operands[i+1].Uint()
break break
} }
} }
@@ -211,7 +211,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Select is much like a ternary operator: it picks a result from // Select is much like a ternary operator: it picks a result from
// the second and third operand based on the boolean first operand. // the second and third operand based on the boolean first operand.
var result value var result value
switch operands[0].Uint(r) { switch operands[0].Uint() {
case 1: case 1:
result = operands[1] result = operands[1]
case 0: case 0:
@@ -282,7 +282,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// by creating a global variable. // by creating a global variable.
// Get the requested memory size to be allocated. // Get the requested memory size to be allocated.
size := operands[1].Uint(r) size := operands[1].Uint()
// Get the object layout, if it is available. // Get the object layout, if it is available.
llvmLayoutType := r.getLLVMTypeFromLayout(operands[2]) llvmLayoutType := r.getLLVMTypeFromLayout(operands[2])
@@ -318,9 +318,9 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// memmove(dst, src, n*elemSize) // memmove(dst, src, n*elemSize)
// return int(n) // return int(n)
// } // }
dstLen := operands[3].Uint(r) dstLen := operands[3].Uint()
srcLen := operands[4].Uint(r) srcLen := operands[4].Uint()
elemSize := operands[5].Uint(r) elemSize := operands[5].Uint()
n := srcLen n := srcLen
if n > dstLen { if n > dstLen {
n = dstLen n = dstLen
@@ -374,7 +374,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil { if err != nil {
return nil, mem, r.errorAt(inst, err) return nil, mem, r.errorAt(inst, err)
} }
nBytes := uint32(operands[3].Uint(r)) nBytes := uint32(operands[3].Uint())
dstObj := mem.getWritable(dst.index()) dstObj := mem.getWritable(dst.index())
dstBuf := dstObj.buffer.asRawValue(r) dstBuf := dstObj.buffer.asRawValue(r)
if mem.get(src.index()).buffer == nil { if mem.get(src.index()).buffer == nil {
@@ -661,8 +661,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// pointer into the underlying object. // pointer into the underlying object.
var offset int64 var offset int64
for i := 1; i < len(operands); i += 2 { for i := 1; i < len(operands); i += 2 {
index := operands[i].Int(r) index := operands[i].Int()
elementSize := operands[i+1].Int(r) elementSize := operands[i+1].Int()
if elementSize < 0 { if elementSize < 0 {
// This is a struct field. // This is a struct field.
offset += index offset += index
@@ -677,7 +677,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err) return nil, mem, r.errorAt(inst, err)
} }
// GEP on fixed pointer value (for example, memory-mapped I/O). // GEP on fixed pointer value (for example, memory-mapped I/O).
ptrValue := operands[0].Uint(r) + uint64(offset) ptrValue := operands[0].Uint() + uint64(offset)
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8)) locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
continue continue
} }
@@ -739,11 +739,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
var lhs, rhs float64 var lhs, rhs float64
switch operands[0].len(r) { switch operands[0].len(r) {
case 8: case 8:
lhs = math.Float64frombits(operands[0].Uint(r)) lhs = math.Float64frombits(operands[0].Uint())
rhs = math.Float64frombits(operands[1].Uint(r)) rhs = math.Float64frombits(operands[1].Uint())
case 4: case 4:
lhs = float64(math.Float32frombits(uint32(operands[0].Uint(r)))) lhs = float64(math.Float32frombits(uint32(operands[0].Uint())))
rhs = float64(math.Float32frombits(uint32(operands[1].Uint(r)))) rhs = float64(math.Float32frombits(uint32(operands[1].Uint())))
default: default:
panic("unknown float type") panic("unknown float type")
} }
@@ -782,23 +782,23 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if inst.opcode == llvm.Add { if inst.opcode == llvm.Add {
// This likely means this is part of a // This likely means this is part of a
// unsafe.Pointer(uintptr(ptr) + offset) pattern. // unsafe.Pointer(uintptr(ptr) + offset) pattern.
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint(r))) lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
if err != nil { if err != nil {
return nil, mem, r.errorAt(inst, err) return nil, mem, r.errorAt(inst, err)
} }
locals[inst.localIndex] = lhsPtr locals[inst.localIndex] = lhsPtr
} else if inst.opcode == llvm.Xor && rhs.Uint(r) == 0 { } else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
// Special workaround for strings.noescape, see // Special workaround for strings.noescape, see
// src/strings/builder.go in the Go source tree. This is // src/strings/builder.go in the Go source tree. This is
// the identity operator, so we can return the input. // the identity operator, so we can return the input.
locals[inst.localIndex] = lhs locals[inst.localIndex] = lhs
} else if inst.opcode == llvm.And && rhs.Uint(r) < 8 { } else if inst.opcode == llvm.And && rhs.Uint() < 8 {
// This is probably part of a pattern to get the lower bits // This is probably part of a pattern to get the lower bits
// of a pointer for pointer tagging, like this: // of a pointer for pointer tagging, like this:
// uintptr(unsafe.Pointer(t)) & 0b11 // uintptr(unsafe.Pointer(t)) & 0b11
// We can actually support this easily by ANDing with the // We can actually support this easily by ANDing with the
// pointer offset. // pointer offset.
result := uint64(lhsPtr.offset()) & rhs.Uint(r) result := uint64(lhsPtr.offset()) & rhs.Uint()
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8)) locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
} else { } else {
// Catch-all for weird operations that should just be done // Catch-all for weird operations that should just be done
@@ -813,31 +813,31 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
var result uint64 var result uint64
switch inst.opcode { switch inst.opcode {
case llvm.Add: case llvm.Add:
result = lhs.Uint(r) + rhs.Uint(r) result = lhs.Uint() + rhs.Uint()
case llvm.Sub: case llvm.Sub:
result = lhs.Uint(r) - rhs.Uint(r) result = lhs.Uint() - rhs.Uint()
case llvm.Mul: case llvm.Mul:
result = lhs.Uint(r) * rhs.Uint(r) result = lhs.Uint() * rhs.Uint()
case llvm.UDiv: case llvm.UDiv:
result = lhs.Uint(r) / rhs.Uint(r) result = lhs.Uint() / rhs.Uint()
case llvm.SDiv: case llvm.SDiv:
result = uint64(lhs.Int(r) / rhs.Int(r)) result = uint64(lhs.Int() / rhs.Int())
case llvm.URem: case llvm.URem:
result = lhs.Uint(r) % rhs.Uint(r) result = lhs.Uint() % rhs.Uint()
case llvm.SRem: case llvm.SRem:
result = uint64(lhs.Int(r) % rhs.Int(r)) result = uint64(lhs.Int() % rhs.Int())
case llvm.Shl: case llvm.Shl:
result = lhs.Uint(r) << rhs.Uint(r) result = lhs.Uint() << rhs.Uint()
case llvm.LShr: case llvm.LShr:
result = lhs.Uint(r) >> rhs.Uint(r) result = lhs.Uint() >> rhs.Uint()
case llvm.AShr: case llvm.AShr:
result = uint64(lhs.Int(r) >> rhs.Uint(r)) result = uint64(lhs.Int() >> rhs.Uint())
case llvm.And: case llvm.And:
result = lhs.Uint(r) & rhs.Uint(r) result = lhs.Uint() & rhs.Uint()
case llvm.Or: case llvm.Or:
result = lhs.Uint(r) | rhs.Uint(r) result = lhs.Uint() | rhs.Uint()
case llvm.Xor: case llvm.Xor:
result = lhs.Uint(r) ^ rhs.Uint(r) result = lhs.Uint() ^ rhs.Uint()
default: default:
panic("unreachable") panic("unreachable")
} }
@@ -855,11 +855,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// and then truncating it as necessary. // and then truncating it as necessary.
var value uint64 var value uint64
if inst.opcode == llvm.SExt { if inst.opcode == llvm.SExt {
value = uint64(operands[0].Int(r)) value = uint64(operands[0].Int())
} else { } else {
value = operands[0].Uint(r) value = operands[0].Uint()
} }
bitwidth := operands[1].Uint(r) bitwidth := operands[1].Uint()
if r.debug { if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth) fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
} }
@@ -868,11 +868,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
var value float64 var value float64
switch inst.opcode { switch inst.opcode {
case llvm.SIToFP: case llvm.SIToFP:
value = float64(operands[0].Int(r)) value = float64(operands[0].Int())
case llvm.UIToFP: case llvm.UIToFP:
value = float64(operands[0].Uint(r)) value = float64(operands[0].Uint())
} }
bitwidth := operands[1].Uint(r) bitwidth := operands[1].Uint()
if r.debug { if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth) fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
} }
@@ -918,21 +918,21 @@ func (r *runner) interpretICmp(lhs, rhs value, predicate llvm.IntPredicate) bool
} }
return result return result
case llvm.IntUGT: case llvm.IntUGT:
return lhs.Uint(r) > rhs.Uint(r) return lhs.Uint() > rhs.Uint()
case llvm.IntUGE: case llvm.IntUGE:
return lhs.Uint(r) >= rhs.Uint(r) return lhs.Uint() >= rhs.Uint()
case llvm.IntULT: case llvm.IntULT:
return lhs.Uint(r) < rhs.Uint(r) return lhs.Uint() < rhs.Uint()
case llvm.IntULE: case llvm.IntULE:
return lhs.Uint(r) <= rhs.Uint(r) return lhs.Uint() <= rhs.Uint()
case llvm.IntSGT: case llvm.IntSGT:
return lhs.Int(r) > rhs.Int(r) return lhs.Int() > rhs.Int()
case llvm.IntSGE: case llvm.IntSGE:
return lhs.Int(r) >= rhs.Int(r) return lhs.Int() >= rhs.Int()
case llvm.IntSLT: case llvm.IntSLT:
return lhs.Int(r) < rhs.Int(r) return lhs.Int() < rhs.Int()
case llvm.IntSLE: case llvm.IntSLE:
return lhs.Int(r) <= rhs.Int(r) return lhs.Int() <= rhs.Int()
default: default:
// _should_ be unreachable, until LLVM adds new icmp operands (unlikely) // _should_ be unreachable, until LLVM adds new icmp operands (unlikely)
panic("interp: unsupported icmp") panic("interp: unsupported icmp")
+35 -41
View File
@@ -361,8 +361,8 @@ type value interface {
clone() value clone() value
asPointer(*runner) (pointerValue, error) asPointer(*runner) (pointerValue, error)
asRawValue(*runner) rawValue asRawValue(*runner) rawValue
Uint(*runner) uint64 Uint() uint64
Int(*runner) int64 Int() int64
toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error) toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
String() string String() string
} }
@@ -405,8 +405,7 @@ func (v literalValue) len(r *runner) uint32 {
} }
func (v literalValue) String() string { func (v literalValue) String() string {
// Note: passing a nil *runner to v.Int because we know it won't use it. return strconv.FormatInt(v.Int(), 10)
return strconv.FormatInt(v.Int(nil), 10)
} }
func (v literalValue) clone() value { func (v literalValue) clone() value {
@@ -422,13 +421,13 @@ func (v literalValue) asRawValue(r *runner) rawValue {
switch value := v.value.(type) { switch value := v.value.(type) {
case uint64: case uint64:
buf = make([]byte, 8) buf = make([]byte, 8)
r.byteOrder.PutUint64(buf, value) binary.LittleEndian.PutUint64(buf, value)
case uint32: case uint32:
buf = make([]byte, 4) buf = make([]byte, 4)
r.byteOrder.PutUint32(buf, uint32(value)) binary.LittleEndian.PutUint32(buf, uint32(value))
case uint16: case uint16:
buf = make([]byte, 2) buf = make([]byte, 2)
r.byteOrder.PutUint16(buf, uint16(value)) binary.LittleEndian.PutUint16(buf, uint16(value))
case uint8: case uint8:
buf = []byte{uint8(value)} buf = []byte{uint8(value)}
default: default:
@@ -441,7 +440,7 @@ func (v literalValue) asRawValue(r *runner) rawValue {
return raw return raw
} }
func (v literalValue) Uint(r *runner) uint64 { func (v literalValue) Uint() uint64 {
switch value := v.value.(type) { switch value := v.value.(type) {
case uint64: case uint64:
return value return value
@@ -456,7 +455,7 @@ func (v literalValue) Uint(r *runner) uint64 {
} }
} }
func (v literalValue) Int(r *runner) int64 { func (v literalValue) Int() int64 {
switch value := v.value.(type) { switch value := v.value.(type) {
case uint64: case uint64:
return int64(value) return int64(value)
@@ -554,11 +553,11 @@ func (v pointerValue) asRawValue(r *runner) rawValue {
return rv return rv
} }
func (v pointerValue) Uint(r *runner) uint64 { func (v pointerValue) Uint() uint64 {
panic("cannot convert pointer to integer") panic("cannot convert pointer to integer")
} }
func (v pointerValue) Int(r *runner) int64 { func (v pointerValue) Int() int64 {
panic("cannot convert pointer to integer") panic("cannot convert pointer to integer")
} }
@@ -703,12 +702,7 @@ func (v rawValue) String() string {
} }
// Format as number if none of the buf is a pointer. // Format as number if none of the buf is a pointer.
if !v.hasPointer() { if !v.hasPointer() {
// Construct a fake runner, which is little endian. return strconv.FormatInt(v.Int(), 10)
// We only use String() for debugging, so this is is good enough
// (the printed value will just be slightly wrong when debugging the
// interp package with GOOS=mips for example).
r := &runner{byteOrder: binary.LittleEndian}
return strconv.FormatInt(v.Int(r), 10)
} }
} }
return "<[…" + strconv.Itoa(len(v.buf)) + "]>" return "<[…" + strconv.Itoa(len(v.buf)) + "]>"
@@ -744,33 +738,33 @@ func (v rawValue) bytes() []byte {
return buf return buf
} }
func (v rawValue) Uint(r *runner) uint64 { func (v rawValue) Uint() uint64 {
buf := v.bytes() buf := v.bytes()
switch len(v.buf) { switch len(v.buf) {
case 1: case 1:
return uint64(buf[0]) return uint64(buf[0])
case 2: case 2:
return uint64(r.byteOrder.Uint16(buf)) return uint64(binary.LittleEndian.Uint16(buf))
case 4: case 4:
return uint64(r.byteOrder.Uint32(buf)) return uint64(binary.LittleEndian.Uint32(buf))
case 8: case 8:
return r.byteOrder.Uint64(buf) return binary.LittleEndian.Uint64(buf)
default: default:
panic("unknown integer size") panic("unknown integer size")
} }
} }
func (v rawValue) Int(r *runner) int64 { func (v rawValue) Int() int64 {
switch len(v.buf) { switch len(v.buf) {
case 1: case 1:
return int64(int8(v.Uint(r))) return int64(int8(v.Uint()))
case 2: case 2:
return int64(int16(v.Uint(r))) return int64(int16(v.Uint()))
case 4: case 4:
return int64(int32(v.Uint(r))) return int64(int32(v.Uint()))
case 8: case 8:
return int64(int64(v.Uint(r))) return int64(int64(v.Uint()))
default: default:
panic("unknown integer size") panic("unknown integer size")
} }
@@ -884,11 +878,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
var n uint64 var n uint64
switch llvmType.IntTypeWidth() { switch llvmType.IntTypeWidth() {
case 64: case 64:
n = rawValue{v.buf[:8]}.Uint(mem.r) n = rawValue{v.buf[:8]}.Uint()
case 32: case 32:
n = rawValue{v.buf[:4]}.Uint(mem.r) n = rawValue{v.buf[:4]}.Uint()
case 16: case 16:
n = rawValue{v.buf[:2]}.Uint(mem.r) n = rawValue{v.buf[:2]}.Uint()
case 8: case 8:
n = uint64(v.buf[0]) n = uint64(v.buf[0])
case 1: case 1:
@@ -957,7 +951,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
} }
// This is either a null pointer or a raw pointer for memory-mapped I/O // This is either a null pointer or a raw pointer for memory-mapped I/O
// (such as 0xe000ed00). // (such as 0xe000ed00).
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint(mem.r) ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint()
if ptr == 0 { if ptr == 0 {
// Null pointer. // Null pointer.
return llvm.ConstNull(llvmType), nil return llvm.ConstNull(llvmType), nil
@@ -975,11 +969,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
} }
return llvm.ConstIntToPtr(ptrValue, llvmType), nil return llvm.ConstIntToPtr(ptrValue, llvmType), nil
case llvm.DoubleTypeKind: case llvm.DoubleTypeKind:
b := rawValue{v.buf[:8]}.Uint(mem.r) b := rawValue{v.buf[:8]}.Uint()
f := math.Float64frombits(b) f := math.Float64frombits(b)
return llvm.ConstFloat(llvmType, f), nil return llvm.ConstFloat(llvmType, f), nil
case llvm.FloatTypeKind: case llvm.FloatTypeKind:
b := uint32(rawValue{v.buf[:4]}.Uint(mem.r)) b := uint32(rawValue{v.buf[:4]}.Uint())
f := math.Float32frombits(b) f := math.Float32frombits(b)
return llvm.ConstFloat(llvmType, float64(f)), nil return llvm.ConstFloat(llvmType, float64(f)), nil
default: default:
@@ -1071,19 +1065,19 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
switch llvmValue.Type().IntTypeWidth() { switch llvmValue.Type().IntTypeWidth() {
case 64: case 64:
var buf [8]byte var buf [8]byte
r.byteOrder.PutUint64(buf[:], n) binary.LittleEndian.PutUint64(buf[:], n)
for i, b := range buf { for i, b := range buf {
v.buf[i] = uint64(b) v.buf[i] = uint64(b)
} }
case 32: case 32:
var buf [4]byte var buf [4]byte
r.byteOrder.PutUint32(buf[:], uint32(n)) binary.LittleEndian.PutUint32(buf[:], uint32(n))
for i, b := range buf { for i, b := range buf {
v.buf[i] = uint64(b) v.buf[i] = uint64(b)
} }
case 16: case 16:
var buf [2]byte var buf [2]byte
r.byteOrder.PutUint16(buf[:], uint16(n)) binary.LittleEndian.PutUint16(buf[:], uint16(n))
for i, b := range buf { for i, b := range buf {
v.buf[i] = uint64(b) v.buf[i] = uint64(b)
} }
@@ -1115,14 +1109,14 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
case llvm.DoubleTypeKind: case llvm.DoubleTypeKind:
f, _ := llvmValue.DoubleValue() f, _ := llvmValue.DoubleValue()
var buf [8]byte var buf [8]byte
r.byteOrder.PutUint64(buf[:], math.Float64bits(f)) binary.LittleEndian.PutUint64(buf[:], math.Float64bits(f))
for i, b := range buf { for i, b := range buf {
v.buf[i] = uint64(b) v.buf[i] = uint64(b)
} }
case llvm.FloatTypeKind: case llvm.FloatTypeKind:
f, _ := llvmValue.DoubleValue() f, _ := llvmValue.DoubleValue()
var buf [4]byte var buf [4]byte
r.byteOrder.PutUint32(buf[:], math.Float32bits(float32(f))) binary.LittleEndian.PutUint32(buf[:], math.Float32bits(float32(f)))
for i, b := range buf { for i, b := range buf {
v.buf[i] = uint64(b) v.buf[i] = uint64(b)
} }
@@ -1172,11 +1166,11 @@ func (v localValue) asRawValue(r *runner) rawValue {
panic("interp: localValue.asRawValue") panic("interp: localValue.asRawValue")
} }
func (v localValue) Uint(r *runner) uint64 { func (v localValue) Uint() uint64 {
panic("interp: localValue.Uint") panic("interp: localValue.Uint")
} }
func (v localValue) Int(r *runner) int64 { func (v localValue) Int() int64 {
panic("interp: localValue.Int") panic("interp: localValue.Int")
} }
@@ -1260,7 +1254,7 @@ func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
ptr, err := layoutValue.asPointer(r) ptr, err := layoutValue.asPointer(r)
if err == errIntegerAsPointer { if err == errIntegerAsPointer {
// It's an integer, which means it's a small object or unknown. // It's an integer, which means it's a small object or unknown.
layout := layoutValue.Uint(r) layout := layoutValue.Uint()
if layout == 0 { if layout == 0 {
// Nil pointer, which means the layout is unknown. // Nil pointer, which means the layout is unknown.
return 0, nil return 0, nil
@@ -1293,7 +1287,7 @@ func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
// Read the object size in words and the bitmap from the global. // Read the object size in words and the bitmap from the global.
buf := r.objects[ptr.index()].buffer.(rawValue) buf := r.objects[ptr.index()].buffer.(rawValue)
objectSizeWords := rawValue{buf: buf.buf[:r.pointerSize]}.Uint(r) objectSizeWords := rawValue{buf: buf.buf[:r.pointerSize]}.Uint()
rawByteValues := buf.buf[r.pointerSize:] rawByteValues := buf.buf[r.pointerSize:]
rawBytes := make([]byte, len(rawByteValues)) rawBytes := make([]byte, len(rawByteValues))
for i, v := range rawByteValues { for i, v := range rawByteValues {
+1
Submodule lib/renesas-svd added at 03d7688085
+24 -30
View File
@@ -218,7 +218,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
// with the TinyGo version. This is the case on some targets. // with the TinyGo version. This is the case on some targets.
func needsSyscallPackage(buildTags []string) bool { func needsSyscallPackage(buildTags []string) bool {
for _, tag := range buildTags { for _, tag := range buildTags {
if tag == "baremetal" || tag == "nintendoswitch" || tag == "tinygo.wasm" { if tag == "baremetal" || tag == "darwin" || tag == "nintendoswitch" || tag == "tinygo.wasm" {
return true return true
} }
} }
@@ -229,35 +229,29 @@ func needsSyscallPackage(buildTags []string) bool {
// means use the TinyGo version. // means use the TinyGo version.
func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool { func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths := map[string]bool{ paths := map[string]bool{
"": true, "": true,
"crypto/": true, "crypto/": true,
"crypto/rand/": false, "crypto/rand/": false,
"crypto/tls/": false, "crypto/tls/": false,
"crypto/x509/": true, "device/": false,
"crypto/x509/internal/": true, "examples/": false,
"crypto/x509/internal/macos/": false, "internal/": true,
"device/": false, "internal/binary/": false,
"examples/": false, "internal/bytealg/": false,
"internal/": true, "internal/cm/": false,
"internal/abi/": false, "internal/fuzz/": false,
"internal/binary/": false, "internal/reflectlite/": false,
"internal/bytealg/": false, "internal/task/": false,
"internal/cm/": false, "internal/wasi/": false,
"internal/fuzz/": false, "machine/": false,
"internal/reflectlite/": false, "net/": true,
"internal/gclayout": false, "net/http/": false,
"internal/task/": false, "os/": true,
"internal/wasi/": false, "os/user/": false,
"machine/": false, "reflect/": false,
"net/": true, "runtime/": false,
"net/http/": false, "sync/": true,
"os/": true, "testing/": true,
"reflect/": false,
"runtime/": false,
"sync/": true,
"testing/": true,
"tinygo/": false,
"unique/": false,
} }
if goMinor >= 19 { if goMinor >= 19 {
+4 -16
View File
@@ -180,7 +180,7 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
if len(fields) >= 2 { if len(fields) >= 2 {
// There is some file/line/column information. // There is some file/line/column information.
if n, err := strconv.Atoi(fields[len(fields)-2]); err == nil { if n, err := strconv.Atoi(fields[len(fields)-2]); err == nil {
// Format: filename.go:line:column // Format: filename.go:line:colum
pos.Filename = strings.Join(fields[:len(fields)-2], ":") pos.Filename = strings.Join(fields[:len(fields)-2], ":")
pos.Line = n pos.Line = n
pos.Column, _ = strconv.Atoi(fields[len(fields)-1]) pos.Column, _ = strconv.Atoi(fields[len(fields)-1])
@@ -418,12 +418,8 @@ func (p *Package) Check() error {
packageName := p.ImportPath packageName := p.ImportPath
if p == p.program.MainPkg() { if p == p.program.MainPkg() {
if p.Name != "main" { if p.Name != "main" {
return Errors{p, []error{ // Sanity check. Should not ever trigger.
scanner.Error{ panic("expected main package to have name 'main'")
Pos: p.program.fset.Position(p.Files[0].Name.Pos()),
Msg: fmt.Sprintf("expected main package to have name \"main\", not %#v", p.Name),
},
}}
} }
packageName = "main" packageName = "main"
} }
@@ -432,15 +428,7 @@ func (p *Package) Check() error {
if err, ok := err.(Errors); ok { if err, ok := err.(Errors); ok {
return err return err
} }
if len(typeErrors) != 0 { return Errors{p, typeErrors}
// Got type errors, so return them.
return Errors{p, typeErrors}
}
// This can happen in some weird cases.
// The only case I know is when compiling a Go 1.23 program, with a
// TinyGo version that supports Go 1.23 but is compiled using Go 1.22.
// So this should be pretty rare.
return Errors{p, []error{err}}
} }
p.Pkg = typesPkg p.Pkg = typesPkg
+154 -286
View File
@@ -283,6 +283,48 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
// Tests are always run in the package directory. // Tests are always run in the package directory.
cmd.Dir = result.MainDir cmd.Dir = result.MainDir
// wasmtime is the default emulator used for `-target=wasip1`. wasmtime
// is a WebAssembly runtime CLI with WASI enabled by default. However,
// only stdio are allowed by default. For example, while STDOUT routes
// to the host, other files don't. It also does not inherit environment
// variables from the host. Some tests read testdata files, often from
// outside the package directory. Other tests require temporary
// writeable directories. We allow this by adding wasmtime flags below.
if config.EmulatorName() == "wasmtime" {
// At this point, The current working directory is at the package
// directory. Ex. $GOROOT/src/compress/flate for compress/flate.
// buildAndRun has already added arguments for wasmtime, that allow
// read-access to files such as "testdata/huffman-zero.in".
//
// Ex. main(.wasm) --dir=. -- -test.v
// Below adds additional wasmtime flags in case a test reads files
// outside its directory, like "../testdata/e.txt". This allows any
// relative directory up to the module root, even if the test never
// reads any files.
//
// Ex. run --dir=.. --dir=../.. --dir=../../..
var dirs []string
switch config.Options.Target {
case "wasip1":
dirs = dirsToModuleRootRel(result.MainDir, result.ModuleRoot)
case "wasip2":
dirs = dirsToModuleRootAbs(result.MainDir, result.ModuleRoot)
default:
return fmt.Errorf("unknown GOOS target: %v", config.Options.Target)
}
args := []string{"run"}
for _, d := range dirs {
args = append(args, "--dir="+d)
}
args = append(args, "--env=PWD="+cmd.Dir)
args = append(args, cmd.Args[1:]...)
cmd.Args = args
}
// Run the test. // Run the test.
start := time.Now() start := time.Now()
err = cmd.Run() err = cmd.Run()
@@ -766,9 +808,12 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
// buildAndRun builds and runs the given program, writing output to stdout and // buildAndRun builds and runs the given program, writing output to stdout and
// errors to os.Stderr. It takes care of emulators (qemu, wasmtime, etc) and // errors to os.Stderr. It takes care of emulators (qemu, wasmtime, etc) and
// passes command line arguments and environment variables in a way appropriate // passes command line arguments and evironment variables in a way appropriate
// for the given emulator. // for the given emulator.
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) (builder.BuildResult, error) { func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) (builder.BuildResult, error) {
isSingleFile := strings.HasSuffix(pkgName, ".go")
// Determine whether we're on a system that supports environment variables // Determine whether we're on a system that supports environment variables
// and command line parameters (operating systems, WASI) or not (baremetal, // and command line parameters (operating systems, WASI) or not (baremetal,
// WebAssembly in the browser). If we're on a system without an environment, // WebAssembly in the browser). If we're on a system without an environment,
@@ -781,7 +826,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
needsEnvInVars = true needsEnvInVars = true
} }
} }
var args, env []string var args, emuArgs, env []string
var extraCmdEnv []string var extraCmdEnv []string
if needsEnvInVars { if needsEnvInVars {
runtimeGlobals := make(map[string]string) runtimeGlobals := make(map[string]string)
@@ -801,6 +846,21 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
"runtime": runtimeGlobals, "runtime": runtimeGlobals,
} }
} }
} else if config.EmulatorName() == "wasmtime" {
for _, v := range environmentVars {
emuArgs = append(emuArgs, "--env", v)
}
if len(cmdArgs) != 0 {
// Use of '--' argument no longer necessary as of Wasmtime v14:
// https://github.com/bytecodealliance/wasmtime/pull/6946
// args = append(args, "--")
args = append(args, cmdArgs...)
}
// Set this for nicer backtraces during tests, but don't override the user.
if _, ok := os.LookupEnv("WASMTIME_BACKTRACE_DETAILS"); !ok {
extraCmdEnv = append(extraCmdEnv, "WASMTIME_BACKTRACE_DETAILS=1")
}
} else { } else {
// Pass environment variables and command line parameters as usual. // Pass environment variables and command line parameters as usual.
// This also works on qemu-aarch64 etc. // This also works on qemu-aarch64 etc.
@@ -843,61 +903,27 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
return result, err return result, err
} }
name, emulator = emulator[0], emulator[1:] name = emulator[0]
// wasmtime is a WebAssembly runtime CLI with WASI enabled by default.
// By default, only stdio is allowed. For example, while STDOUT routes
// to the host, other files don't. It also does not inherit environment
// variables from the host. Some tests read testdata files, often from
// outside the package directory. Other tests require temporary
// writeable directories. We allow this by adding wasmtime flags below.
if name == "wasmtime" { if name == "wasmtime" {
var emuArgs []string // Wasmtime needs some special flags to pass environment variables
// and allow reading from the current directory.
// Extract the wasmtime subcommand (e.g. "run" or "serve") switch config.Options.Target {
if len(emulator) > 1 { case "wasip1":
emuArgs = append(emuArgs, emulator[0])
emulator = emulator[1:]
}
wd, _ := os.Getwd()
// Below adds additional wasmtime flags in case a test reads files
// outside its directory, like "../testdata/e.txt". This allows any
// relative directory up to the module root, even if the test never
// reads any files.
if config.TestConfig.CompileTestBinary {
// Set working directory to package dir
wd = result.MainDir
// Add relative dirs (../, ../..) up to module root (for wasip1)
dirs := dirsToModuleRootRel(result.MainDir, result.ModuleRoot)
// Add absolute dirs up to module root (for wasip2)
dirs = append(dirs, dirsToModuleRootAbs(result.MainDir, result.ModuleRoot)...)
for _, d := range dirs {
emuArgs = append(emuArgs, "--dir="+d)
}
} else {
emuArgs = append(emuArgs, "--dir=.") emuArgs = append(emuArgs, "--dir=.")
case "wasip2":
dir := result.MainDir
if isSingleFile {
cwd, _ := os.Getwd()
dir = cwd
}
emuArgs = append(emuArgs, "--dir="+dir)
emuArgs = append(emuArgs, "--env=PWD="+dir)
} }
emuArgs = append(emuArgs, "--dir="+wd)
emuArgs = append(emuArgs, "--env=PWD="+wd)
for _, v := range environmentVars {
emuArgs = append(emuArgs, "--env", v)
}
// Set this for nicer backtraces during tests, but don't override the user.
if _, ok := os.LookupEnv("WASMTIME_BACKTRACE_DETAILS"); !ok {
extraCmdEnv = append(extraCmdEnv, "WASMTIME_BACKTRACE_DETAILS=1")
}
emulator = append(emuArgs, emulator...)
} }
args = append(emulator, args...) emuArgs = append(emuArgs, emulator[1:]...)
args = append(emuArgs, args...)
} }
var cmd *exec.Cmd var cmd *exec.Cmd
if ctx != nil { if ctx != nil {
@@ -910,7 +936,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
// Configure stdout/stderr. The stdout may go to a buffer, not a real // Configure stdout/stderr. The stdout may go to a buffer, not a real
// stdout. // stdout.
cmd.Stdout = newOutputWriter(stdout, result.Executable) cmd.Stdout = stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
if config.EmulatorName() == "simavr" { if config.EmulatorName() == "simavr" {
cmd.Stdout = nil // don't print initial load commands cmd.Stdout = nil // don't print initial load commands
@@ -927,12 +953,12 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
// Run binary. // Run binary.
if config.Options.PrintCommands != nil { if config.Options.PrintCommands != nil {
config.Options.PrintCommands(cmd.Path, cmd.Args[1:]...) config.Options.PrintCommands(cmd.Path, cmd.Args...)
} }
err = run(cmd, result) err = run(cmd, result)
if err != nil { if err != nil {
if ctx != nil && ctx.Err() == context.DeadlineExceeded { if ctx != nil && ctx.Err() == context.DeadlineExceeded {
fmt.Fprintf(stdout, "--- timeout of %s exceeded, terminating...\n", timeout) stdout.Write([]byte(fmt.Sprintf("--- timeout of %s exceeded, terminating...\n", timeout)))
err = ctx.Err() err = ctx.Err()
} }
return result, &commandError{"failed to run compiled binary", result.Binary, err} return result, &commandError{"failed to run compiled binary", result.Binary, err}
@@ -1232,169 +1258,36 @@ func getBMPPorts() (gdbPort, uartPort string, err error) {
} }
} }
const (
usageBuild = `Build compiles the packages named by the import paths, along with their
dependencies, but it does not install the results. The output binary is
specified using the -o parameter. The generated file type depends on the
extension:
.o:
Create a relocatable object file. You can use this option if you
don't want to use the TinyGo build system or want to do other custom
things.
.ll:
Create textual LLVM IR, after optimization. This is mainly useful
for debugging.
.bc:
Create LLVM bitcode, after optimization. This may be useful for
debugging or for linking into other programs using LTO.
.hex:
Create an Intel HEX file to flash it to a microcontroller.
.bin:
Similar, but create a binary file.
.wasm:
Compile and link a WebAssembly file.
(all other) Compile and link the program into a regular executable. For
microcontrollers, it is common to use the .elf file extension to indicate a
linked ELF file is generated. For Linux, it is common to build binaries with no
extension at all.`
usageRun = `Run the program, either directly on the host or in an emulated environment
(depending on -target).`
usageFlash = `Flash the program to a microcontroller. Some common flags are described below.
-target={name}:
Specifies the type of microcontroller that is used. The name of the
microcontroller is given on the individual pages for each board type
listed under Microcontrollers
(https://tinygo.org/docs/reference/microcontrollers/).
Examples: "arduino-nano", "d1mini", "xiao".
-monitor:
Start the serial monitor (see below) immediately after
flashing. However, some microcontrollers need a split second
or two to configure the serial port after flashing, and
using the "-monitor" flag can fail because the serial
monitor starts too quickly. In that case, use the "tinygo
monitor" command explicitly.`
usageMonitor = `Start the serial monitor on the serial port that is connected to the
microcontroller. If there is only a single board attached to the host computer,
the default values for various options should be sufficient. In other
situations, particularly if you have multiple microcontrollers attached, some
parameters may need to be overridden using the following flags:
-port={port}:
If there are multiple microcontroller attached, an error
message will display a list of potential serial ports. The
appropriate port can be specified by this flag. On Linux,
the port will be something like /dev/ttyUSB0 or /dev/ttyACM1.
On MacOS, the port will look like /dev/cu.usbserial-1420. On
Windows, the port will be something like COM1 or COM31.
-baudrate={rate}:
The default baud rate is 115200. Boards using the AVR
processor (e.g. Arduino Nano, Arduino Mega 2560) use 9600
instead.
-target={name}:
If you have more than one microcontrollers attached, you can
sometimes just specify the target name and let tinygo
monitor figure out the port. Sometimes, this does not work
and you have to explicitly use the -port flag.
The serial monitor intercepts several control characters for its own use instead of sending them
to the microcontroller:
Control-C: terminates the tinygo monitor
Control-Z: suspends the tinygo monitor and drops back into shell
Control-\: terminates the tinygo monitor with a stack trace
Control-S: flow control, suspends output to the console
Control-Q: flow control, resumes output to the console
Control-@: thrown away by tinygo monitor
Note: If you are using os.Stdin on the microcontroller, you may find that a CR
character on the host computer (also known as Enter, ^M, or \r) is transmitted
to the microcontroller without conversion, so os.Stdin returns a \r character
instead of the expected \n (also known as ^J, NL, or LF) to indicate
end-of-line. You may be able to get around this problem by hitting Control-J in
tinygo monitor to transmit the \n end-of-line character.`
usageGdb = `Build the program, optionally flash it to a microcontroller if it is a remote
target, and drop into a GDB shell. From there you can set breakpoints, start the
program with "run" or "continue" ("run" for a local program, continue for
on-chip debugging), single-step, show a backtrace, break and resume the program
with Ctrl-C/"continue", etc. You may need to install extra tools (like openocd
and arm-none-eabi-gdb) to be able to do this. Also, you may need a dedicated
debugger to be able to debug certain boards if no debugger is integrated. Some
boards (like the BBC micro:bit and most professional evaluation boards) have an
integrated debugger.`
usageClean = `Clean the cache directory, normally stored in $HOME/.cache/tinygo. This is not
normally needed.`
usageHelp = `Print a short summary of the available commands, plus a list of command flags.`
usageVersion = `Print the version of the command and the version of the used $GOROOT.`
usageEnv = `Print a list of environment variables that affect TinyGo (as a shell script).
If one or more variable names are given as arguments, env prints the value of
each on a new line.`
usageDefault = `TinyGo is a Go compiler for small places.
version: %s
usage: %s <command> [arguments]
commands:
build: compile packages and dependencies
run: compile and run immediately
test: test packages
flash: compile and flash to the device
gdb: run/flash and immediately enter GDB
lldb: run/flash and immediately enter LLDB
monitor: open communication port
ports: list available serial ports
env: list environment variables used during build
list: run go list using the TinyGo root
clean: empty cache directory (%s)
targets: list targets
info: show info for specified target
version: show version
help: print this help text`
)
var (
commandHelp = map[string]string{
"build": usageBuild,
"run": usageRun,
"flash": usageFlash,
"monitor": usageMonitor,
"gdb": usageGdb,
"clean": usageClean,
"help": usageHelp,
"version": usageVersion,
"env": usageEnv,
}
)
func usage(command string) { func usage(command string) {
val, ok := commandHelp[command] switch command {
if !ok { default:
fmt.Fprintf(os.Stderr, usageDefault, goenv.Version(), os.Args[0], goenv.Get("GOCACHE")) fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
fmt.Fprintln(os.Stderr, "version:", goenv.Version())
fmt.Fprintf(os.Stderr, "usage: %s <command> [arguments]\n", os.Args[0])
fmt.Fprintln(os.Stderr, "\ncommands:")
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
fmt.Fprintln(os.Stderr, " run: compile and run immediately")
fmt.Fprintln(os.Stderr, " test: test packages")
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
fmt.Fprintln(os.Stderr, " monitor: open communication port")
fmt.Fprintln(os.Stderr, " ports: list available serial ports")
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
fmt.Fprintln(os.Stderr, " targets: list targets")
fmt.Fprintln(os.Stderr, " info: show info for specified target")
fmt.Fprintln(os.Stderr, " version: show version")
fmt.Fprintln(os.Stderr, " help: print this help text")
if flag.Parsed() { if flag.Parsed() {
fmt.Fprintln(os.Stderr, "\nflags:") fmt.Fprintln(os.Stderr, "\nflags:")
flag.PrintDefaults() flag.PrintDefaults()
} }
fmt.Fprintln(os.Stderr, "\nfor more details, see https://tinygo.org/docs/reference/usage/") fmt.Fprintln(os.Stderr, "\nfor more details, see https://tinygo.org/docs/reference/usage/")
} else {
fmt.Fprintln(os.Stderr, val)
} }
} }
func handleCompilerError(err error) { func handleCompilerError(err error) {
@@ -1439,20 +1332,19 @@ func (m globalValuesFlag) Set(value string) error {
// parseGoLinkFlag parses the -ldflags parameter. Its primary purpose right now // parseGoLinkFlag parses the -ldflags parameter. Its primary purpose right now
// is the -X flag, for setting the value of global string variables. // is the -X flag, for setting the value of global string variables.
func parseGoLinkFlag(flagsString string) (map[string]map[string]string, string, error) { func parseGoLinkFlag(flagsString string) (map[string]map[string]string, error) {
set := flag.NewFlagSet("link", flag.ExitOnError) set := flag.NewFlagSet("link", flag.ExitOnError)
globalVarValues := make(globalValuesFlag) globalVarValues := make(globalValuesFlag)
set.Var(globalVarValues, "X", "Set the value of the string variable to the given value.") set.Var(globalVarValues, "X", "Set the value of the string variable to the given value.")
extLDFlags := set.String("extldflags", "", "additional flags to pass to external linker")
flags, err := shlex.Split(flagsString) flags, err := shlex.Split(flagsString)
if err != nil { if err != nil {
return nil, "", err return nil, err
} }
err = set.Parse(flags) err = set.Parse(flags)
if err != nil { if err != nil {
return nil, "", err return nil, err
} }
return map[string]map[string]string(globalVarValues), *extLDFlags, nil return map[string]map[string]string(globalVarValues), nil
} }
// getListOfPackages returns a standard list of packages for a given list that might // getListOfPackages returns a standard list of packages for a given list that might
@@ -1502,7 +1394,6 @@ func main() {
var tags buildutil.TagsFlag var tags buildutil.TagsFlag
flag.Var(&tags, "tags", "a space-separated list of extra build tags") flag.Var(&tags, "tags", "a space-separated list of extra build tags")
target := flag.String("target", "", "chip/board name or JSON target specification file") target := flag.String("target", "", "chip/board name or JSON target specification file")
buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared)")
var stackSize uint64 var stackSize uint64
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error { flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
size, err := bytesize.Parse(s) size, err := bytesize.Parse(s)
@@ -1546,7 +1437,7 @@ func main() {
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list") flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
} }
var outpath string var outpath string
if command == "help" || command == "build" || command == "test" { if command == "help" || command == "build" || command == "build-library" || command == "test" {
flag.StringVar(&outpath, "o", "", "output filename") flag.StringVar(&outpath, "o", "", "output filename")
} }
@@ -1572,20 +1463,18 @@ func main() {
// Early command processing, before commands are interpreted by the Go flag // Early command processing, before commands are interpreted by the Go flag
// library. // library.
handleChdirFlag()
switch command { switch command {
case "clang", "ld.lld", "wasm-ld": case "clang", "ld.lld", "wasm-ld":
err := builder.RunTool(command, os.Args[2:]...) err := builder.RunTool(command, os.Args[2:]...)
if err != nil { if err != nil {
// The tool should have printed an error message already. fmt.Fprintln(os.Stderr, err)
// Don't print another error message here.
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)
} }
flag.CommandLine.Parse(os.Args[2:]) flag.CommandLine.Parse(os.Args[2:])
globalVarValues, extLDFlags, err := parseGoLinkFlag(*ldflags) globalVarValues, err := parseGoLinkFlag(*ldflags)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
@@ -1609,9 +1498,7 @@ func main() {
GOOS: goenv.Get("GOOS"), GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
GOMIPS: goenv.Get("GOMIPS"),
Target: *target, Target: *target,
BuildMode: *buildMode,
StackSize: stackSize, StackSize: stackSize,
Opt: *opt, Opt: *opt,
GC: *gc, GC: *gc,
@@ -1646,14 +1533,6 @@ func main() {
options.PrintCommands = printCommand options.PrintCommands = printCommand
} }
if extLDFlags != "" {
options.ExtLDFlags, err = shlex.Split(extLDFlags)
if err != nil {
fmt.Fprintln(os.Stderr, "could not parse -extldflags:", err)
os.Exit(1)
}
}
err = options.Verify() err = options.Verify()
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err.Error()) fmt.Fprintln(os.Stderr, err.Error())
@@ -1691,6 +1570,50 @@ func main() {
err := Build(pkgName, outpath, options) err := Build(pkgName, outpath, options)
handleCompilerError(err) handleCompilerError(err)
case "build-library":
// Note: this command is only meant to be used while making a release!
if outpath == "" {
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
usage(command)
os.Exit(1)
}
if *target == "" {
fmt.Fprintln(os.Stderr, "No target (-target).")
}
if flag.NArg() != 1 {
fmt.Fprintf(os.Stderr, "Build-library only accepts exactly one library name as argument, %d given\n", flag.NArg())
usage(command)
os.Exit(1)
}
var lib *builder.Library
switch name := flag.Arg(0); name {
case "compiler-rt":
lib = &builder.CompilerRT
case "picolibc":
lib = &builder.Picolibc
default:
fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name)
os.Exit(1)
}
tmpdir, err := os.MkdirTemp("", "tinygo*")
if err != nil {
handleCompilerError(err)
}
defer os.RemoveAll(tmpdir)
spec, err := compileopts.LoadTarget(options)
if err != nil {
handleCompilerError(err)
}
config := &compileopts.Config{
Options: options,
Target: spec,
}
path, err := lib.Load(config, tmpdir)
handleCompilerError(err)
err = copyFile(path, outpath)
if err != nil {
handleCompilerError(err)
}
case "flash", "gdb", "lldb": case "flash", "gdb", "lldb":
pkgName := filepath.ToSlash(flag.Arg(0)) pkgName := filepath.ToSlash(flag.Arg(0))
if command == "flash" { if command == "flash" {
@@ -1750,7 +1673,7 @@ func main() {
for i := range bufs { for i := range bufs {
err := bufs[i].flush(os.Stdout, os.Stderr) err := bufs[i].flush(os.Stdout, os.Stderr)
if err != nil { if err != nil {
// There was an error writing to stdout or stderr, so we probably cannot print this. // There was an error writing to stdout or stderr, so we probbably cannot print this.
select { select {
case fail <- struct{}{}: case fail <- struct{}{}:
default: default:
@@ -1857,7 +1780,6 @@ func main() {
GOOS string `json:"goos"` GOOS string `json:"goos"`
GOARCH string `json:"goarch"` GOARCH string `json:"goarch"`
GOARM string `json:"goarm"` GOARM string `json:"goarm"`
GOMIPS string `json:"gomips"`
BuildTags []string `json:"build_tags"` BuildTags []string `json:"build_tags"`
GC string `json:"garbage_collector"` GC string `json:"garbage_collector"`
Scheduler string `json:"scheduler"` Scheduler string `json:"scheduler"`
@@ -1868,7 +1790,6 @@ func main() {
GOOS: config.GOOS(), GOOS: config.GOOS(),
GOARCH: config.GOARCH(), GOARCH: config.GOARCH(),
GOARM: config.GOARM(), GOARM: config.GOARM(),
GOMIPS: config.GOMIPS(),
BuildTags: config.BuildTags(), BuildTags: config.BuildTags(),
GC: config.GC(), GC: config.GC(),
Scheduler: config.Scheduler(), Scheduler: config.Scheduler(),
@@ -2067,56 +1988,3 @@ type outputEntry struct {
stderr bool stderr bool
data []byte data []byte
} }
// handleChdirFlag handles the -C flag before doing anything else.
// The -C flag must be the first flag on the command line, to make it easy to find
// even with commands that have custom flag parsing.
// handleChdirFlag handles the flag by chdir'ing to the directory
// and then removing that flag from the command line entirely.
//
// We have to handle the -C flag this way for two reasons:
//
// 1. Toolchain selection needs to be in the right directory to look for go.mod and go.work.
//
// 2. A toolchain switch later on reinvokes the new go command with the same arguments.
// The parent toolchain has already done the chdir; the child must not try to do it again.
func handleChdirFlag() {
used := 2 // b.c. command at os.Args[1]
if used >= len(os.Args) {
return
}
var dir string
switch a := os.Args[used]; {
default:
return
case a == "-C", a == "--C":
if used+1 >= len(os.Args) {
return
}
dir = os.Args[used+1]
os.Args = slicesDelete(os.Args, used, used+2)
case strings.HasPrefix(a, "-C="), strings.HasPrefix(a, "--C="):
_, dir, _ = strings.Cut(a, "=")
os.Args = slicesDelete(os.Args, used, used+1)
}
if err := os.Chdir(dir); err != nil {
fmt.Fprintln(os.Stderr, "cannot chdir:", err)
os.Exit(1)
}
}
// go1.19 compatibility: lacks slices package
func slicesDelete[S ~[]E, E any](s S, i, j int) S {
_ = s[i:j:len(s)] // bounds check
if i == j {
return s
}
return append(s[:i], s[j:]...)
}
+41 -449
View File
@@ -6,29 +6,25 @@ package main
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"crypto/sha256"
"errors" "errors"
"flag" "flag"
"fmt"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
"strconv" "slices"
"strings" "strings"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/aykevl/go-wasm" "github.com/aykevl/go-wasm"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
"github.com/tinygo-org/tinygo/builder" "github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
@@ -41,7 +37,7 @@ var supportedLinuxArches = map[string]string{
"X86Linux": "linux/386", "X86Linux": "linux/386",
"ARMLinux": "linux/arm/6", "ARMLinux": "linux/arm/6",
"ARM64Linux": "linux/arm64", "ARM64Linux": "linux/arm64",
"MIPSLinux": "linux/mips/hardfloat", "MIPSLinux": "linux/mipsle",
"WASIp1": "wasip1/wasm", "WASIp1": "wasip1/wasm",
} }
@@ -80,7 +76,6 @@ func TestBuild(t *testing.T) {
"oldgo/", "oldgo/",
"print.go", "print.go",
"reflect.go", "reflect.go",
"signal.go",
"slice.go", "slice.go",
"sort.go", "sort.go",
"stdlib.go", "stdlib.go",
@@ -103,9 +98,6 @@ func TestBuild(t *testing.T) {
if minor >= 22 { if minor >= 22 {
tests = append(tests, "go1.22/") tests = append(tests, "go1.22/")
} }
if minor >= 23 {
tests = append(tests, "go1.23/")
}
if *testTarget != "" { if *testTarget != "" {
// This makes it possible to run one specific test (instead of all), // This makes it possible to run one specific test (instead of all),
@@ -115,15 +107,10 @@ func TestBuild(t *testing.T) {
return return
} }
t.Run("Debugging", func(t *testing.T) { t.Run("Host", func(t *testing.T) {
for i := 0; i < 5; i++ { t.Parallel()
t.Run(strconv.Itoa(i), func(t *testing.T) { runPlatTests(optionsFromTarget("", sema), tests, t)
options := optionsFromTarget("", sema)
runTest("alias.go", options, t, nil, nil)
})
}
}) })
return
// Test a few build options. // Test a few build options.
t.Run("build-options", func(t *testing.T) { t.Run("build-options", func(t *testing.T) {
@@ -188,15 +175,6 @@ func TestBuild(t *testing.T) {
}) })
} }
} }
t.Run("MIPS little-endian", func(t *testing.T) {
// Run a single test for GOARCH=mipsle to see whether it works at
// all. It is already mostly tested because GOARCH=mips and
// GOARCH=mipsle are so similar, but it's good to have an extra test
// to be sure.
t.Parallel()
options := optionsFromOSARCH("linux/mipsle/softfloat", sema)
runTest("cgo/", options, t, nil, nil)
})
t.Run("WebAssembly", func(t *testing.T) { t.Run("WebAssembly", func(t *testing.T) {
t.Parallel() t.Parallel()
runPlatTests(optionsFromTarget("wasm", sema), tests, t) runPlatTests(optionsFromTarget("wasm", sema), tests, t)
@@ -224,7 +202,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// isWebAssembly := strings.HasPrefix(spec.Triple, "wasm") // isWebAssembly := strings.HasPrefix(spec.Triple, "wasm")
isWASI := strings.HasPrefix(options.Target, "wasi") isWASI := strings.HasPrefix(options.Target, "wasi")
isWebAssembly := isWASI || strings.HasPrefix(options.Target, "wasm") || (options.Target == "" && strings.HasPrefix(options.GOARCH, "wasm")) isWebAssembly := isWASI || strings.HasPrefix(options.Target, "wasm") || (options.Target == "" && strings.HasPrefix(options.GOARCH, "wasm"))
isBaremetal := options.Target == "simavr" || options.Target == "cortex-m-qemu" || options.Target == "riscv-qemu"
for _, name := range tests { for _, name := range tests {
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") { if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
@@ -236,18 +213,11 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
} }
} }
if options.GOOS == "linux" && (options.GOARCH == "mips" || options.GOARCH == "mipsle") { if options.GOOS == "linux" && (options.GOARCH == "mips" || options.GOARCH == "mipsle") {
if name == "atomic.go" || name == "timers.go" { if name == "atomic.go" {
// 64-bit atomic operations aren't currently supported on MIPS. // 64-bit atomic operations aren't currently supported on MIPS.
continue continue
} }
} }
if options.GOOS == "linux" && options.GOARCH == "mips" {
if name == "cgo/" {
// CGo isn't supported yet on big-endian systems (needs updates
// to bitfield access methods).
continue
}
}
if options.Target == "simavr" { if options.Target == "simavr" {
// Not all tests are currently supported on AVR. // Not all tests are currently supported on AVR.
// Skip the ones that aren't. // Skip the ones that aren't.
@@ -274,11 +244,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// some compiler changes). // some compiler changes).
continue continue
case "timers.go":
// Crashes starting with Go 1.23.
// Bug: https://github.com/llvm/llvm-project/issues/104032
continue
default: default:
} }
} }
@@ -289,13 +254,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
continue continue
} }
} }
if isWebAssembly || isBaremetal || options.GOOS == "windows" {
switch name {
case "signal.go":
// Signals only work on POSIX-like systems.
continue
}
}
name := name // redefine to avoid race condition name := name // redefine to avoid race condition
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
@@ -368,7 +326,6 @@ func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
GOOS: goenv.Get("GOOS"), GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
GOMIPS: goenv.Get("GOMIPS"),
Target: target, Target: target,
Semaphore: sema, Semaphore: sema,
InterpTimeout: 180 * time.Second, InterpTimeout: 180 * time.Second,
@@ -392,11 +349,8 @@ func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
VerifyIR: true, VerifyIR: true,
Opt: "z", Opt: "z",
} }
switch options.GOARCH { if options.GOARCH == "arm" {
case "arm":
options.GOARM = parts[2] options.GOARM = parts[2]
case "mips", "mipsle":
options.GOMIPS = parts[2]
} }
return options return options
} }
@@ -411,13 +365,17 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
// of the path. // of the path.
path := TESTDATA + "/" + name path := TESTDATA + "/" + name
// Get the expected output for this test. // Get the expected output for this test.
expectedOutputPath := path[:len(path)-3] + ".txt" txtpath := path[:len(path)-3] + ".txt"
pkgName := "./" + path pkgName := "./" + path
if path[len(path)-1] == '/' { if path[len(path)-1] == '/' {
expectedOutputPath = path + "out.txt" txtpath = path + "out.txt"
options.Directory = path options.Directory = path
pkgName = "." pkgName = "."
} }
expected, err := os.ReadFile(txtpath)
if err != nil {
t.Fatal("could not read expected output file:", err)
}
config, err := builder.NewConfig(&options) config, err := builder.NewConfig(&options)
if err != nil { if err != nil {
@@ -426,68 +384,23 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
// Build the test binary. // Build the test binary.
stdout := &bytes.Buffer{} stdout := &bytes.Buffer{}
_, fileExt := config.EmulatorFormat() _, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
tmpdir := t.TempDir() return cmd.Run()
result, err := builder.Build(pkgName, fileExt, tmpdir, config) })
if err != nil { if err != nil {
t.Fatal("build failed:", err) w := &bytes.Buffer{}
diagnostics.CreateDiagnostics(err).WriteTo(w, "")
for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") {
t.Log(line)
}
t.Fail()
return
} }
data, err := os.ReadFile(result.Executable) // putchar() prints CRLF, convert it to LF.
if err != nil { actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
t.Fatal("failed to read executable:", err) expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
}
hash := sha256.Sum256(data)
t.Logf("executable hash and size: %d %x", len(data), hash)
for i := 0; i < 100; i++ {
i := i
t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
stdout := &bytes.Buffer{}
cmd := exec.Command(result.Executable)
cmd.Stdout = stdout
cmd.Stderr = stdout
err := cmd.Run()
if err != nil {
t.Log("run error:", err)
}
checkOutput(t, expectedOutputPath, stdout.Bytes())
})
}
return
//_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
// data, err := os.ReadFile(result.Executable)
// if err != nil {
// t.Fatal("failed to read executable:", err)
// }
// hash := sha256.Sum256(data)
// t.Logf("executable hash and size: %d %x", len(data), hash)
// t.Log("command:", cmd)
// err = cmd.Run()
// if err == nil {
// t.Log(" error is nil!")
// } else {
// t.Log(" error:", err)
// }
// return err
//})
//if err != nil {
// w := &bytes.Buffer{}
// diagnostics.CreateDiagnostics(err).WriteTo(w, "")
// for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") {
// t.Log(line)
// }
// if stdout.Len() != 0 {
// t.Logf("output:\n%s", stdout.String())
// }
// t.Fail()
// return
//}
actual := stdout.Bytes()
if config.EmulatorName() == "simavr" { if config.EmulatorName() == "simavr" {
// Strip simavr log formatting. // Strip simavr log formatting.
actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1) actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1)
@@ -502,12 +415,17 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
} }
// Check whether the command ran successfully. // Check whether the command ran successfully.
fail := false
if err != nil { if err != nil {
t.Error("failed to run:", err) t.Log("failed to run:", err)
fail = true
} else if !bytes.Equal(expected, actual) {
t.Logf("output did not match (expected %d bytes, got %d bytes):", len(expected), len(actual))
t.Logf(string(Diff("expected", expected, "actual", actual)))
fail = true
} }
checkOutput(t, expectedOutputPath, actual)
if t.Failed() { if fail {
r := bufio.NewReader(bytes.NewReader(actual)) r := bufio.NewReader(bytes.NewReader(actual))
for { for {
line, err := r.ReadString('\n') line, err := r.ReadString('\n')
@@ -525,21 +443,20 @@ func TestWebAssembly(t *testing.T) {
t.Parallel() t.Parallel()
type testCase struct { type testCase struct {
name string name string
target string
panicStrategy string panicStrategy string
imports []string imports []string
} }
for _, tc := range []testCase{ for _, tc := range []testCase{
// Test whether there really are no imports when using -panic=trap. This // Test whether there really are no imports when using -panic=trap. This
// tests the bugfix for https://github.com/tinygo-org/tinygo/issues/4161. // tests the bugfix for https://github.com/tinygo-org/tinygo/issues/4161.
{name: "panic-default", target: "wasip1", imports: []string{"wasi_snapshot_preview1.fd_write", "wasi_snapshot_preview1.random_get"}}, {name: "panic-default", imports: []string{"wasi_snapshot_preview1.fd_write"}},
{name: "panic-trap", target: "wasm-unknown", panicStrategy: "trap", imports: []string{}}, {name: "panic-trap", panicStrategy: "trap", imports: []string{}},
} { } {
tc := tc tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
t.Parallel() t.Parallel()
tmpdir := t.TempDir() tmpdir := t.TempDir()
options := optionsFromTarget(tc.target, sema) options := optionsFromTarget("wasi", sema)
options.PanicStrategy = tc.panicStrategy options.PanicStrategy = tc.panicStrategy
config, err := builder.NewConfig(&options) config, err := builder.NewConfig(&options)
if err != nil { if err != nil {
@@ -571,7 +488,7 @@ func TestWebAssembly(t *testing.T) {
} }
} }
} }
if !stringSlicesEqual(imports, tc.imports) { if !slices.Equal(imports, tc.imports) {
t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports) t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports)
} }
} }
@@ -579,330 +496,6 @@ func TestWebAssembly(t *testing.T) {
} }
} }
func stringSlicesEqual(s1, s2 []string) bool {
// We can use slices.Equal once we drop support for Go 1.20 (it was added in
// Go 1.21).
if len(s1) != len(s2) {
return false
}
for i, s := range s1 {
if s != s2[i] {
return false
}
}
return true
}
func TestWasmExport(t *testing.T) {
t.Parallel()
type testCase struct {
name string
target string
buildMode string
scheduler string
file string
noOutput bool
command bool // call _start (command mode) instead of _initialize
}
tests := []testCase{
// "command mode" WASI
{
name: "WASIp1-command",
target: "wasip1",
command: true,
},
// "reactor mode" WASI (with -buildmode=c-shared)
{
name: "WASIp1-reactor",
target: "wasip1",
buildMode: "c-shared",
},
// Make sure reactor mode also works without a scheduler.
{
name: "WASIp1-reactor-noscheduler",
target: "wasip1",
buildMode: "c-shared",
scheduler: "none",
file: "wasmexport-noscheduler.go",
},
// Test -target=wasm-unknown with the default build mode (which is
// c-shared).
{
name: "wasm-unknown-reactor",
target: "wasm-unknown",
file: "wasmexport-noscheduler.go",
noOutput: true, // wasm-unknown cannot produce output
},
// Test -target=wasm-unknown with -buildmode=default, which makes it run
// in command mode.
{
name: "wasm-unknown-command",
target: "wasm-unknown",
buildMode: "default",
file: "wasmexport-noscheduler.go",
noOutput: true, // wasm-unknown cannot produce output
command: true,
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Build the wasm binary.
tmpdir := t.TempDir()
options := optionsFromTarget(tc.target, sema)
options.BuildMode = tc.buildMode
options.Scheduler = tc.scheduler
buildConfig, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}
filename := "wasmexport.go"
if tc.file != "" {
filename = tc.file
}
result, err := builder.Build("testdata/"+filename, ".wasm", tmpdir, buildConfig)
if err != nil {
t.Fatal("failed to build binary:", err)
}
// Read the wasm binary back into memory.
data, err := os.ReadFile(result.Binary)
if err != nil {
t.Fatal("could not read wasm binary: ", err)
}
// Set up the wazero runtime.
output := &bytes.Buffer{}
ctx := context.Background()
r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
defer r.Close(ctx)
config := wazero.NewModuleConfig().
WithStdout(output).WithStderr(output).
WithStartFunctions()
// Prepare for testing.
var mod api.Module
mustCall := func(results []uint64, err error) []uint64 {
if err != nil {
t.Error("failed to run function:", err)
}
return results
}
checkResult := func(name string, results []uint64, expected []uint64) {
if len(results) != len(expected) {
t.Errorf("%s: expected %v but got %v", name, expected, results)
}
for i, result := range results {
if result != expected[i] {
t.Errorf("%s: expected %v but got %v", name, expected, results)
break
}
}
}
runTests := func() {
// Test an exported function without params or return value.
checkResult("hello()", mustCall(mod.ExportedFunction("hello").Call(ctx)), nil)
// Test that we can call an exported function more than once.
checkResult("add(3, 5)", mustCall(mod.ExportedFunction("add").Call(ctx, 3, 5)), []uint64{8})
checkResult("add(7, 9)", mustCall(mod.ExportedFunction("add").Call(ctx, 7, 9)), []uint64{16})
checkResult("add(6, 1)", mustCall(mod.ExportedFunction("add").Call(ctx, 6, 1)), []uint64{7})
// Test that imported functions can call exported functions
// again.
checkResult("reentrantCall(2, 3)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 2, 3)), []uint64{5})
checkResult("reentrantCall(1, 8)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 1, 8)), []uint64{9})
}
// Add wasip1 module.
wasi_snapshot_preview1.MustInstantiate(ctx, r)
// Add custom "tester" module.
callOutside := func(a, b int32) int32 {
results, err := mod.ExportedFunction("add").Call(ctx, uint64(a), uint64(b))
if err != nil {
t.Error("could not call exported add function:", err)
}
return int32(results[0])
}
callTestMain := func() {
runTests()
}
builder := r.NewHostModuleBuilder("tester")
builder.NewFunctionBuilder().WithFunc(callOutside).Export("callOutside")
builder.NewFunctionBuilder().WithFunc(callTestMain).Export("callTestMain")
_, err = builder.Instantiate(ctx)
if err != nil {
t.Fatal(err)
}
// Parse and instantiate the wasm.
mod, err = r.InstantiateWithConfig(ctx, data, config)
if err != nil {
t.Fatal("could not instantiate wasm module:", err)
}
// Initialize the module and run the tests.
if tc.command {
// Call _start (the entry point), which calls
// tester.callTestMain, which then runs all the tests.
_, err := mod.ExportedFunction("_start").Call(ctx)
if err != nil {
if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() == 0 {
// Exited with code 0. Nothing to worry about.
} else {
t.Error("failed to run _start:", err)
}
}
} else {
// Run the _initialize call, because this is reactor mode wasm.
mustCall(mod.ExportedFunction("_initialize").Call(ctx))
runTests()
}
// Check that the output matches the expected output.
// (Skip this for wasm-unknown because it can't produce output).
if !tc.noOutput {
checkOutput(t, "testdata/wasmexport.txt", output.Bytes())
}
})
}
}
// Test js.FuncOf (for syscall/js).
// This test might be extended in the future to cover more cases in syscall/js.
func TestWasmFuncOf(t *testing.T) {
// Build the wasm binary.
tmpdir := t.TempDir()
options := optionsFromTarget("wasm", sema)
buildConfig, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}
result, err := builder.Build("testdata/wasmfunc.go", ".wasm", tmpdir, buildConfig)
if err != nil {
t.Fatal("failed to build binary:", err)
}
// Test the resulting binary using NodeJS.
output := &bytes.Buffer{}
cmd := exec.Command("node", "testdata/wasmfunc.js", result.Binary, buildConfig.BuildMode())
cmd.Stdout = output
cmd.Stderr = output
err = cmd.Run()
if err != nil {
t.Error("failed to run node:", err)
}
checkOutput(t, "testdata/wasmfunc.txt", output.Bytes())
}
// Test //go:wasmexport in JavaScript (using NodeJS).
func TestWasmExportJS(t *testing.T) {
t.Parallel()
type testCase struct {
name string
buildMode string
}
tests := []testCase{
{name: "default"},
{name: "c-shared", buildMode: "c-shared"},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Build the wasm binary.
tmpdir := t.TempDir()
options := optionsFromTarget("wasm", sema)
options.BuildMode = tc.buildMode
buildConfig, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}
result, err := builder.Build("testdata/wasmexport-noscheduler.go", ".wasm", tmpdir, buildConfig)
if err != nil {
t.Fatal("failed to build binary:", err)
}
// Test the resulting binary using NodeJS.
output := &bytes.Buffer{}
cmd := exec.Command("node", "testdata/wasmexport.js", result.Binary, buildConfig.BuildMode())
cmd.Stdout = output
cmd.Stderr = output
err = cmd.Run()
if err != nil {
t.Error("failed to run node:", err)
}
checkOutput(t, "testdata/wasmexport.txt", output.Bytes())
})
}
}
// Test whether Go.run() (in wasm_exec.js) normally returns and returns the
// right exit code.
func TestWasmExit(t *testing.T) {
t.Parallel()
type testCase struct {
name string
output string
}
tests := []testCase{
{name: "normal", output: "exit code: 0\n"},
{name: "exit-0", output: "exit code: 0\n"},
{name: "exit-0-sleep", output: "slept\nexit code: 0\n"},
{name: "exit-1", output: "exit code: 1\n"},
{name: "exit-1-sleep", output: "slept\nexit code: 1\n"},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
options := optionsFromTarget("wasm", sema)
buildConfig, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}
buildConfig.Target.Emulator = "node testdata/wasmexit.js {}"
output := &bytes.Buffer{}
_, err = buildAndRun("testdata/wasmexit.go", buildConfig, output, []string{tc.name}, nil, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run()
})
if err != nil {
t.Error(err)
}
expected := "wasmexit test: " + tc.name + "\n" + tc.output
checkOutputData(t, []byte(expected), output.Bytes())
})
}
}
// Check whether the output of a test equals the expected output.
func checkOutput(t *testing.T, filename string, actual []byte) {
expectedOutput, err := os.ReadFile(filename)
if err != nil {
t.Fatal("could not read output file:", err)
}
checkOutputData(t, expectedOutput, actual)
}
func checkOutputData(t *testing.T, expectedOutput, actual []byte) {
expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n"))
actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n"))
if !bytes.Equal(actual, expectedOutput) {
t.Errorf("output did not match (expected %d bytes, got %d bytes):", len(expectedOutput), len(actual))
t.Error(string(Diff("expected", expectedOutput, "actual", actual)))
}
}
func TestTest(t *testing.T) { func TestTest(t *testing.T) {
t.Parallel() t.Parallel()
@@ -1103,8 +696,7 @@ func TestMain(m *testing.M) {
// Invoke a specific tool. // Invoke a specific tool.
err := builder.RunTool(os.Args[1], os.Args[2:]...) err := builder.RunTool(os.Args[1], os.Args[2:]...)
if err != nil { if err != nil {
// The tool should have printed an error message already. fmt.Fprintln(os.Stderr, err)
// Don't print another error message here.
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)
-41
View File
@@ -1,41 +0,0 @@
acces,access
acuire,acquire
addess,address
adust,adjust
allcoate,allocate
alloated,allocated
archtecture,architecture
arcive,archive
ardiuno,arduino
beconfigured,be configured
calcluate,calculate
colum,column
configration,configuration
contants,constants
cricital,critical
deffered,deferred
evaulator,evaluator
evironment,environment
freqency,frequency
frquency,frequency
implmented,implemented
interrput,interrupt
interrut,interrupt
interupt,interrupt
measuing,measuring
numer of,number of
orignal,original
overrided,overridden
poiners,pointers
poitner,pointer
probbably,probably
recogized,recognized
refection,reflection
requries,requires
satisifying,satisfying
simulataneously,simultaneously
suggets,suggests
transmition,transmission
undefied,undefined
unecessary,unnecessary
unsiged,unsigned
1 acces access
2 acuire acquire
3 addess address
4 adust adjust
5 allcoate allocate
6 alloated allocated
7 archtecture architecture
8 arcive archive
9 ardiuno arduino
10 beconfigured be configured
11 calcluate calculate
12 colum column
13 configration configuration
14 contants constants
15 cricital critical
16 deffered deferred
17 evaulator evaluator
18 evironment environment
19 freqency frequency
20 frquency frequency
21 implmented implemented
22 interrput interrupt
23 interrut interrupt
24 interupt interrupt
25 measuing measuring
26 numer of number of
27 orignal original
28 overrided overridden
29 poiners pointers
30 poitner pointer
31 probbably probably
32 recogized recognized
33 refection reflection
34 requries requires
35 satisifying satisfying
36 simulataneously simultaneously
37 suggets suggests
38 transmition transmission
39 undefied undefined
40 unecessary unnecessary
41 unsiged unsigned
+19 -41
View File
@@ -197,14 +197,31 @@ func Monitor(executable, port string, config *compileopts.Config) error {
go func() { go func() {
buf := make([]byte, 100*1024) buf := make([]byte, 100*1024)
writer := newOutputWriter(os.Stdout, executable) var line []byte
for { for {
n, err := serialConn.Read(buf) n, err := serialConn.Read(buf)
if err != nil { if err != nil {
errCh <- fmt.Errorf("read error: %w", err) errCh <- fmt.Errorf("read error: %w", err)
return return
} }
writer.Write(buf[:n]) start := 0
for i, c := range buf[:n] {
if c == '\n' {
os.Stdout.Write(buf[start : i+1])
start = i + 1
address := extractPanicAddress(line)
if address != 0 {
loc, err := addressToLine(executable, address)
if err == nil && loc.IsValid() {
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
}
}
line = line[:0]
} else {
line = append(line, c)
}
}
os.Stdout.Write(buf[start:n])
} }
}() }()
@@ -383,42 +400,3 @@ func readDWARF(executable string) (*dwarf.Data, error) {
return nil, errors.New("unknown binary format") return nil, errors.New("unknown binary format")
} }
} }
type outputWriter struct {
out io.Writer
executable string
line []byte
}
// newOutputWriter returns an io.Writer that will intercept panic addresses and
// will try to insert a source location in the output if the source location can
// be found in the executable.
func newOutputWriter(out io.Writer, executable string) *outputWriter {
return &outputWriter{
out: out,
executable: executable,
}
}
func (w *outputWriter) Write(p []byte) (n int, err error) {
start := 0
for i, c := range p {
if c == '\n' {
w.out.Write(p[start : i+1])
start = i + 1
address := extractPanicAddress(w.line)
if address != 0 {
loc, err := addressToLine(w.executable, address)
if err == nil && loc.Filename != "" {
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
}
}
w.line = w.line[:0]
} else {
w.line = append(w.line, c)
}
}
w.out.Write(p[start:])
n = len(p)
return
}
+1 -1
View File
@@ -3,7 +3,7 @@
// This implementation of crypto/rand uses the arc4random_buf function // This implementation of crypto/rand uses the arc4random_buf function
// (available on both MacOS and WASI) to generate random numbers. // (available on both MacOS and WASI) to generate random numbers.
// //
// Note: arc4random_buf (unlike what the name suggests) does not use the insecure // Note: arc4random_buf (unlike what the name suggets) does not use the insecure
// RC4 cipher. Instead, it uses a high-quality cipher, varying by the libc // RC4 cipher. Instead, it uses a high-quality cipher, varying by the libc
// implementation. // implementation.
+1 -1
View File
@@ -101,7 +101,7 @@ type Dialer struct {
// //
// The returned Conn, if any, will always be of type *Conn. // The returned Conn, if any, will always be of type *Conn.
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
return nil, errors.New("tls:DialContext not implemented") return nil, errors.New("tls:DialContext not implmented")
} }
// LoadX509KeyPair reads and parses a public/private key pair from a pair // LoadX509KeyPair reads and parses a public/private key pair from a pair
-185
View File
@@ -1,185 +0,0 @@
package macos
import (
"errors"
"time"
)
// Exported symbols copied from Big Go, but stripped of functionality.
// Allows building of crypto/x509 on macOS.
const (
ErrSecCertificateExpired = -67818
ErrSecHostNameMismatch = -67602
ErrSecNotTrusted = -67843
)
var ErrNoTrustSettings = errors.New("no trust settings found")
var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO
var SecPolicyOid = StringToCFString("SecPolicyOid")
var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy")
var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString")
var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult")
func CFArrayAppendValue(array CFRef, val CFRef) {}
func CFArrayGetCount(array CFRef) int {
return 0
}
func CFDataGetBytePtr(data CFRef) uintptr {
return 0
}
func CFDataGetLength(data CFRef) int {
return 0
}
func CFDataToSlice(data CFRef) []byte {
return nil
}
func CFEqual(a, b CFRef) bool {
return false
}
func CFErrorGetCode(errRef CFRef) int {
return 0
}
func CFNumberGetValue(num CFRef) (int32, error) {
return 0, errors.New("not implemented")
}
func CFRelease(ref CFRef) {}
func CFStringToString(ref CFRef) string {
return ""
}
func ReleaseCFArray(array CFRef) {}
func SecCertificateCopyData(cert CFRef) ([]byte, error) {
return nil, errors.New("not implemented")
}
func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
return 0, errors.New("not implemented")
}
func SecTrustGetCertificateCount(trustObj CFRef) int {
return 0
}
func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) {
return 0, 0, errors.New("not implemented")
}
func SecTrustSetVerifyDate(trustObj CFRef, dateRef CFRef) error {
return errors.New("not implemented")
}
type CFRef uintptr
func BytesToCFData(b []byte) CFRef {
return 0
}
func CFArrayCreateMutable() CFRef {
return 0
}
func CFArrayGetValueAtIndex(array CFRef, index int) CFRef {
return 0
}
func CFDateCreate(seconds float64) CFRef {
return 0
}
func CFDictionaryGetValueIfPresent(dict CFRef, key CFString) (value CFRef, ok bool) {
return 0, false
}
func CFErrorCopyDescription(errRef CFRef) CFRef {
return 0
}
func CFStringCreateExternalRepresentation(strRef CFRef) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecCertificateCreateWithData(b []byte) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecPolicyCreateSSL(name string) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecTrustEvaluate(trustObj CFRef) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) {
return 0, errors.New("not implemented")
}
func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) {
return 0, errors.New("not implemented")
}
func TimeToCFDateRef(t time.Time) CFRef {
return 0
}
type CFString CFRef
func StringToCFString(s string) CFString {
return 0
}
type OSStatus struct {
// Has unexported fields.
}
func (s OSStatus) Error() string
type SecTrustResultType int32
const (
SecTrustResultInvalid SecTrustResultType = iota
SecTrustResultProceed
SecTrustResultConfirm // deprecated
SecTrustResultDeny
SecTrustResultUnspecified
SecTrustResultRecoverableTrustFailure
SecTrustResultFatalTrustFailure
SecTrustResultOtherError
)
type SecTrustSettingsDomain int32
const (
SecTrustSettingsDomainUser SecTrustSettingsDomain = iota
SecTrustSettingsDomainAdmin
SecTrustSettingsDomainSystem
)
type SecTrustSettingsResult int32
const (
SecTrustSettingsResultInvalid SecTrustSettingsResult = iota
SecTrustSettingsResultTrustRoot
SecTrustSettingsResultTrustAsRoot
SecTrustSettingsResultDeny
SecTrustSettingsResultUnspecified
)
-2
View File
@@ -1,2 +0,0 @@
// Package abi exposes low-level details of the Go compiler/runtime
package abi
-10
View File
@@ -1,10 +0,0 @@
package abi
import "unsafe"
// Tell the compiler the given pointer doesn't escape.
// The compiler knows about this function and will give the nocapture parameter
// attribute.
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
return p
}

Some files were not shown because too many files have changed in this diff Show More