mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-28 15:48:40 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89ffb47a0c | |||
| 2f7952ff29 |
@@ -107,9 +107,9 @@ jobs:
|
||||
# "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
|
||||
test-llvm18-go123:
|
||||
test-llvm18-go122:
|
||||
docker:
|
||||
- image: golang:1.23-bullseye
|
||||
- image: golang:1.22-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "18"
|
||||
@@ -122,4 +122,4 @@ workflows:
|
||||
# least the smoke tests still pass.
|
||||
- test-llvm15-go119
|
||||
# This tests LLVM 18 support when linking against system libraries.
|
||||
- test-llvm18-go123
|
||||
- test-llvm18-go122
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
open_collective: tinygo
|
||||
@@ -16,17 +16,18 @@ jobs:
|
||||
name: build-macos
|
||||
strategy:
|
||||
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)
|
||||
os: [macos-13, macos-14]
|
||||
os: [macos-12, macos-14]
|
||||
include:
|
||||
- os: macos-13
|
||||
- os: macos-12
|
||||
goarch: amd64
|
||||
- os: macos-14
|
||||
goarch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
@@ -36,7 +37,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -71,6 +72,7 @@ jobs:
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
# fetch LLVM source
|
||||
rm -rf llvm-project
|
||||
@@ -98,12 +100,14 @@ jobs:
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
- name: Test TinyGo
|
||||
shell: bash
|
||||
run: make test GOTESTFLAGS="-short"
|
||||
- name: Build TinyGo release tarball
|
||||
run: make release -j3
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test
|
||||
- name: Make release artifact
|
||||
shell: bash
|
||||
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
@@ -117,6 +121,7 @@ jobs:
|
||||
name: darwin-${{ matrix.goarch }}-double-zipped
|
||||
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||
test-macos-homebrew:
|
||||
name: homebrew-install
|
||||
@@ -140,7 +145,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.23-alpine
|
||||
image: golang:1.22-alpine
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v4
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
@@ -184,7 +184,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
@@ -307,7 +307,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
|
||||
@@ -15,11 +15,6 @@ jobs:
|
||||
nix-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- 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
|
||||
uses: actions/checkout@v4
|
||||
- name: Pull musl
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# still works after checking out the dev branch (that is, when going from LLVM
|
||||
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
|
||||
|
||||
echo 'deb https://apt.llvm.org/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 -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
|
||||
@@ -9,8 +9,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
sizediff:
|
||||
# Note: when updating the Ubuntu version, also update the Ubuntu version in
|
||||
# sizediff-install-pkgs.sh
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -20,8 +20,6 @@ src/device/stm32/*.go
|
||||
src/device/stm32/*.s
|
||||
src/device/kendryte/*.go
|
||||
src/device/kendryte/*.s
|
||||
src/device/renesas/*.go
|
||||
src/device/renesas/*.s
|
||||
src/device/rp/*.go
|
||||
src/device/rp/*.s
|
||||
./vendor
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
[submodule "lib/macos-minimal-sdk"]
|
||||
path = lib/macos-minimal-sdk
|
||||
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"]
|
||||
path = src/net
|
||||
url = https://github.com/tinygo-org/net.git
|
||||
|
||||
+1
-111
@@ -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
|
||||
---
|
||||
|
||||
@@ -2006,7 +1896,7 @@
|
||||
- allow packages like github.com/tinygo-org/tinygo/src/\* by aliasing it
|
||||
- remove `//go:volatile` support
|
||||
It has been replaced with the runtime/volatile package.
|
||||
- allow pointers in map keys
|
||||
- allow poiners in map keys
|
||||
- support non-constant syscall numbers
|
||||
- implement non-blocking selects
|
||||
- add support for the `-tags` flag
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# 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 && \
|
||||
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
|
||||
# all the build tools etc).
|
||||
FROM golang:1.23 AS tinygo-compiler
|
||||
FROM golang:1.22 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
+11
-51
@@ -185,7 +185,7 @@ fmt-check: ## Warn if any source needs reformatting
|
||||
@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 ## Generate microcontroller-specific sources
|
||||
ifneq ($(STM32), 0)
|
||||
gen-device: gen-device-stm32
|
||||
endif
|
||||
@@ -234,7 +234,7 @@ gen-device-rp: build/gen-device-svd
|
||||
GO111MODULE=off $(GO) fmt ./src/device/rp
|
||||
|
||||
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
|
||||
|
||||
$(LLVM_PROJECTDIR)/llvm:
|
||||
@@ -267,7 +267,7 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
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
|
||||
WASM_TOOLS_MODULE=github.com/bytecodealliance/wasm-tools-go
|
||||
WASM_TOOLS_MODULE=github.com/ydnar/wasm-tools-go
|
||||
.PHONY: wasi-syscall
|
||||
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
|
||||
@@ -293,7 +293,7 @@ tinygo: ## Build the TinyGo compiler
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " $(MAKE) llvm-source"; echo " $(MAKE) $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
test: wasi-libc check-nodejs-version
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
|
||||
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
|
||||
TEST_PACKAGES_SLOW = \
|
||||
@@ -303,34 +303,26 @@ TEST_PACKAGES_SLOW = \
|
||||
|
||||
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
|
||||
TEST_PACKAGES_FAST = \
|
||||
cmp \
|
||||
compress/lzw \
|
||||
compress/zlib \
|
||||
container/heap \
|
||||
container/list \
|
||||
container/ring \
|
||||
crypto/des \
|
||||
crypto/ecdsa \
|
||||
crypto/elliptic \
|
||||
crypto/md5 \
|
||||
crypto/rc4 \
|
||||
crypto/sha1 \
|
||||
crypto/sha256 \
|
||||
crypto/sha512 \
|
||||
database/sql/driver \
|
||||
debug/macho \
|
||||
embed/internal/embedtest \
|
||||
encoding \
|
||||
encoding/ascii85 \
|
||||
encoding/asn1 \
|
||||
encoding/base32 \
|
||||
encoding/base64 \
|
||||
encoding/csv \
|
||||
encoding/hex \
|
||||
go/ast \
|
||||
go/format \
|
||||
go/scanner \
|
||||
go/version \
|
||||
hash \
|
||||
hash/adler32 \
|
||||
hash/crc64 \
|
||||
@@ -352,7 +344,6 @@ TEST_PACKAGES_FAST = \
|
||||
unicode \
|
||||
unicode/utf16 \
|
||||
unicode/utf8 \
|
||||
unique \
|
||||
$(nil)
|
||||
|
||||
# Assume this will go away before Go2, so only check minor version.
|
||||
@@ -365,41 +356,30 @@ endif
|
||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
||||
# bytes requires mmap
|
||||
# compress/flate appears to hang on wasi
|
||||
# crypto/aes fails on wasi, needs panic()/recover()
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# image requires recover(), which is not yet supported on wasi
|
||||
# image requires recover(), which is not yet supported on 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
|
||||
# net/mail: needs wasip1 syscall.FDFLAG_NONBLOCK
|
||||
# net/ntextproto: needs wasip1 syscall.FDFLAG_NONBLOCK
|
||||
# regexp/syntax: fails on wasip1; needs panic()/recover()
|
||||
# strconv requires recover() which is not yet supported on wasi
|
||||
# text/tabwriter requires recover(), which is not yet supported on wasi
|
||||
# text/tabwriter requries recover(), which is not yet supported on wasi
|
||||
# text/template/parse requires recover(), which is not yet supported on wasi
|
||||
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
|
||||
# Additional standard library packages that pass tests on individual platforms
|
||||
TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
bytes \
|
||||
compress/flate \
|
||||
crypto/aes \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
image \
|
||||
io/ioutil \
|
||||
mime \
|
||||
mime/multipart \
|
||||
mime/quotedprintable \
|
||||
net \
|
||||
net/mail \
|
||||
net/textproto \
|
||||
os/user \
|
||||
regexp/syntax \
|
||||
strconv \
|
||||
testing/fstest \
|
||||
text/tabwriter \
|
||||
text/template/parse
|
||||
|
||||
@@ -408,7 +388,6 @@ TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
TEST_PACKAGES_WINDOWS := \
|
||||
compress/flate \
|
||||
crypto/hmac \
|
||||
os/user \
|
||||
strconv \
|
||||
text/template/parse \
|
||||
$(nil)
|
||||
@@ -503,17 +482,8 @@ tinygo-baremetal:
|
||||
# regression test for #2666: e.g. encoding/hex must pass on baremetal
|
||||
$(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
|
||||
smoketest: testchdir
|
||||
smoketest:
|
||||
$(TINYGO) version
|
||||
$(TINYGO) targets > /dev/null
|
||||
# regression test for #2892
|
||||
@@ -671,8 +641,6 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=rak4631 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pyportal examples/dac
|
||||
@@ -835,20 +803,12 @@ ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
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
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest
|
||||
@$(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
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
|
||||
@@ -1003,11 +963,11 @@ lint: tools ## Lint source tree
|
||||
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
|
||||
spell: tools ## Spellcheck source tree
|
||||
misspell -error --dict misspell.csv -i 'ackward,devided,extint,rela' $$( $(SPELLDIRSCMD) ) *.go *.md
|
||||
misspell -error --dict misspell.csv -i 'ackward,devided,extint,rela' $$( $(SPELLDIRSCMD) ) *.md
|
||||
|
||||
.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
|
||||
misspell -w --dict misspell.csv -i 'ackward,devided,extint,rela' $$( $(SPELLDIRSCMD) ) *.md
|
||||
|
||||
# https://www.client9.com/self-documenting-makefiles/
|
||||
.PHONY: help
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -150,7 +150,7 @@ func makeArchive(arfile *os.File, objs []string) error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
// the correct file start indices.
|
||||
offset, err := arfile.Seek(0, io.SeekCurrent)
|
||||
offset, err := arfile.Seek(0, os.SEEK_CUR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+18
-23
@@ -197,7 +197,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
ABI: config.ABI(),
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
BuildMode: config.BuildMode(),
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
SizeLevel: sizeLevel,
|
||||
@@ -650,13 +649,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
result.Binary = result.Executable // final file
|
||||
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
|
||||
// a cache.
|
||||
if config.Target.RTLib == "compiler-rt" {
|
||||
@@ -755,6 +747,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
|
||||
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
|
||||
ldflags = append(ldflags, "-mllvm", "-wasm-enable-eh")
|
||||
if config.GOOS() == "windows" {
|
||||
// Options for the MinGW wrapper for the lld COFF linker.
|
||||
ldflags = append(ldflags,
|
||||
@@ -831,13 +824,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
args = append(args, "--asyncify")
|
||||
}
|
||||
|
||||
inputFile := result.Binary
|
||||
result.Binary = result.Executable + ".wasmopt"
|
||||
exeunopt := result.Executable
|
||||
|
||||
if config.Options.Work {
|
||||
// Keep the work direction around => don't overwrite the .wasm binary with the optimized version
|
||||
exeunopt += ".pre-wasm-opt"
|
||||
os.Rename(result.Executable, exeunopt)
|
||||
}
|
||||
|
||||
args = append(args,
|
||||
opt,
|
||||
"-g",
|
||||
inputFile,
|
||||
"--output", result.Binary,
|
||||
exeunopt,
|
||||
"--output", result.Executable,
|
||||
)
|
||||
|
||||
wasmopt := goenv.Get("WASMOPT")
|
||||
@@ -867,15 +866,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
|
||||
// wasm-tools component embed -w wasi:cli/command
|
||||
// $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm
|
||||
componentEmbedInputFile := result.Binary
|
||||
result.Binary = result.Executable + ".wasm-component-embed"
|
||||
args := []string{
|
||||
"component",
|
||||
"embed",
|
||||
"-w", witWorld,
|
||||
witPackage,
|
||||
componentEmbedInputFile,
|
||||
"-o", result.Binary,
|
||||
result.Executable,
|
||||
"-o", result.Executable,
|
||||
}
|
||||
|
||||
wasmtools := goenv.Get("WASMTOOLS")
|
||||
@@ -888,17 +885,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
|
||||
err := cmd.Run()
|
||||
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
|
||||
componentNewInputFile := result.Binary
|
||||
result.Binary = result.Executable + ".wasm-component-new"
|
||||
args = []string{
|
||||
"component",
|
||||
"new",
|
||||
componentNewInputFile,
|
||||
"-o", result.Binary,
|
||||
result.Executable,
|
||||
"-o", result.Executable,
|
||||
}
|
||||
|
||||
if config.Options.PrintCommands != nil {
|
||||
@@ -910,7 +905,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("`wasm-tools component new` failed: %w", err)
|
||||
return fmt.Errorf("wasm-tools failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,7 +1260,7 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
|
||||
}
|
||||
|
||||
// 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.
|
||||
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
|
||||
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
|
||||
|
||||
@@ -53,12 +53,9 @@ func TestClangAttributes(t *testing.T) {
|
||||
for _, options := range []*compileopts.Options{
|
||||
{GOOS: "linux", GOARCH: "386"},
|
||||
{GOOS: "linux", GOARCH: "amd64"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "5,softfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "6,softfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "7,softfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "5,hardfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "6,hardfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "7,hardfloat"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "5"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "6"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "7"},
|
||||
{GOOS: "linux", GOARCH: "arm64"},
|
||||
{GOOS: "linux", GOARCH: "mips", GOMIPS: "hardfloat"},
|
||||
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "hardfloat"},
|
||||
|
||||
@@ -3,6 +3,7 @@ package builder
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"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], " "))
|
||||
}
|
||||
|
||||
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
@@ -2,7 +2,6 @@ package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
@@ -24,37 +23,20 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
spec.OpenOCDCommands = options.OpenOCDCommands
|
||||
}
|
||||
|
||||
// Version range supported by TinyGo.
|
||||
const minorMin = 19
|
||||
const minorMax = 23
|
||||
|
||||
// Check that we support this Go toolchain version.
|
||||
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
|
||||
major, minor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
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:
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 nil, fmt.Errorf("requires go version 1.19 through 1.22, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
return &compileopts.Config{
|
||||
Options: options,
|
||||
Target: spec,
|
||||
GoMinorVersion: gorootMinor,
|
||||
GoMinorVersion: minor,
|
||||
TestConfig: options.TestConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+16
-6
@@ -17,6 +17,14 @@ import (
|
||||
// concurrency or performance issues.
|
||||
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.
|
||||
// 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.
|
||||
@@ -47,11 +55,12 @@ func dummyCompileJob(result string) *compileJob {
|
||||
// ordered as such in the job dependencies.
|
||||
func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
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())
|
||||
}
|
||||
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.
|
||||
@@ -72,10 +81,10 @@ func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
|
||||
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
|
||||
dependents := make(map[*compileJob][]*compileJob, len(jobs))
|
||||
compileJobs := make(map[*compileJob]int)
|
||||
jidx := make(map[*compileJob]int)
|
||||
var ready intHeap
|
||||
for i, job := range jobs {
|
||||
compileJobs[job] = i
|
||||
jidx[job] = i
|
||||
if len(job.dependencies) == 0 {
|
||||
// This job is ready to run.
|
||||
ready.Push(i)
|
||||
@@ -96,7 +105,8 @@ func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
// Create a channel to accept notifications of completion.
|
||||
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
|
||||
var totalTime time.Duration
|
||||
start := time.Now()
|
||||
@@ -146,7 +156,7 @@ func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
delete(wait, completed)
|
||||
if len(wait) == 0 {
|
||||
// This job is now ready to run.
|
||||
ready.Push(compileJobs[j])
|
||||
ready.Push(jidx[j])
|
||||
delete(waiting, j)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +173,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
// Use softfloat instead of floating point instructions. This is
|
||||
// supported on many architectures.
|
||||
args = append(args, "-msoft-float")
|
||||
} else {
|
||||
if strings.HasPrefix(target, "armv5") {
|
||||
// On ARMv5 we need to explicitly enable hardware floating point
|
||||
// instructions: Clang appears to assume the hardware doesn't have a
|
||||
// FPU otherwise.
|
||||
args = append(args, "-mfpu=vfpv2")
|
||||
}
|
||||
}
|
||||
|
||||
var once sync.Once
|
||||
|
||||
@@ -128,7 +128,6 @@ var libMusl = Library{
|
||||
"mman/*.c",
|
||||
"math/*.c",
|
||||
"multibyte/*.c",
|
||||
"signal/" + arch + "/*.s",
|
||||
"signal/*.c",
|
||||
"stdio/*.c",
|
||||
"string/*.c",
|
||||
|
||||
@@ -41,9 +41,9 @@ func TestBinarySize(t *testing.T) {
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4568, 280, 0, 2268},
|
||||
{"microbit", "examples/serial", 2868, 388, 8, 2272},
|
||||
{"wioterminal", "examples/pininterrupt", 6104, 1484, 116, 6832},
|
||||
{"hifive1b", "examples/echo", 4484, 280, 0, 2252},
|
||||
{"microbit", "examples/serial", 2732, 388, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6016, 1484, 116, 6816},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
|
||||
+6
-19
@@ -14,29 +14,16 @@ import (
|
||||
|
||||
// runCCompiler invokes a C compiler with the given arguments.
|
||||
func runCCompiler(flags ...string) error {
|
||||
// Find the right command to run Clang.
|
||||
var cmd *exec.Cmd
|
||||
if hasBuiltinTools {
|
||||
// Compile this with the internal Clang compiler.
|
||||
cmd = exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
|
||||
} else {
|
||||
// Compile this with an external invocation of the Clang compiler.
|
||||
name, err := LookupCommand("clang")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd = exec.Command(name, flags...)
|
||||
cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
// Make sure the command doesn't use any environmental variables.
|
||||
// Most importantly, it should not use C_INCLUDE_PATH and the like. But
|
||||
// removing all environmental variables also works.
|
||||
cmd.Env = []string{}
|
||||
|
||||
return cmd.Run()
|
||||
// Compile this with an external invocation of the Clang compiler.
|
||||
return execCommand("clang", flags...)
|
||||
}
|
||||
|
||||
// link invokes a linker with the given name and flags.
|
||||
|
||||
+1
-8
@@ -162,13 +162,6 @@ func __GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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
|
||||
@@ -225,7 +218,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
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
|
||||
// resolved.
|
||||
decl.Name.Name = "C." + decl.Name.Name
|
||||
|
||||
Vendored
-7
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
Vendored
-7
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
Vendored
-7
@@ -44,13 +44,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
Vendored
-7
@@ -29,13 +29,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
Vendored
-7
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
Vendored
-7
@@ -24,13 +24,6 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
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 (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
|
||||
@@ -33,17 +33,6 @@ func (c *Config) CPU() string {
|
||||
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
|
||||
// RISC-V processor, that could be "+a,+c,+m". For many targets, an empty list
|
||||
// will be returned.
|
||||
@@ -95,7 +84,6 @@ func (c *Config) BuildTags() []string {
|
||||
tags = append(tags, []string{
|
||||
"tinygo", // that's the compiler
|
||||
"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
|
||||
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
|
||||
"serial." + c.Serial()}...) // used inside the machine package
|
||||
@@ -406,16 +394,6 @@ func (c *Config) LDFlags() []string {
|
||||
if c.Target.LinkerScript != "" {
|
||||
ldflags = append(ldflags, "-T", c.Target.LinkerScript)
|
||||
}
|
||||
|
||||
if c.Options.ExtLDFlags != "" {
|
||||
ext, err := shlex.Split(c.Options.ExtLDFlags)
|
||||
if err != nil {
|
||||
// if shlex can't split it, pass it as-is and let the external linker complain
|
||||
ext = []string{c.Options.ExtLDFlags}
|
||||
}
|
||||
ldflags = append(ldflags, ext...)
|
||||
}
|
||||
|
||||
return ldflags
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
validBuildModeOptions = []string{"default", "c-shared"}
|
||||
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
|
||||
@@ -27,7 +26,6 @@ type Options struct {
|
||||
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
|
||||
Directory string // working dir, leave it unset to use the current working dir
|
||||
Target string
|
||||
BuildMode string // -buildmode flag
|
||||
Opt string
|
||||
GC string
|
||||
PanicStrategy string
|
||||
@@ -58,19 +56,10 @@ type Options struct {
|
||||
Timeout time.Duration
|
||||
WITPackage string // pass through to wasm-tools component embed invocation
|
||||
WITWorld string // pass through to wasm-tools component embed -w option
|
||||
ExtLDFlags string
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
func (o *Options) Verify() error {
|
||||
if o.BuildMode != "" {
|
||||
valid := isInArray(validBuildModeOptions, o.BuildMode)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid buildmode option '%s': valid values are %s`,
|
||||
o.BuildMode,
|
||||
strings.Join(validBuildModeOptions, ", "))
|
||||
}
|
||||
}
|
||||
if o.GC != "" {
|
||||
valid := isInArray(validGCOptions, o.GC)
|
||||
if !valid {
|
||||
|
||||
+12
-69
@@ -32,7 +32,6 @@ type TargetSpec struct {
|
||||
GOARCH string `json:"goarch,omitempty"`
|
||||
SoftFloat bool // used for non-baremetal systems (GOMIPS=softfloat etc)
|
||||
BuildTags []string `json:"build-tags,omitempty"`
|
||||
BuildMode string `json:"buildmode,omitempty"` // default build mode (if nothing specified)
|
||||
GC string `json:"gc,omitempty"`
|
||||
Scheduler string `json:"scheduler,omitempty"`
|
||||
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
|
||||
@@ -268,60 +267,18 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
case "arm":
|
||||
spec.CPU = "generic"
|
||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||
subarch := strings.Split(options.GOARM, ",")
|
||||
if len(subarch) > 2 {
|
||||
return nil, fmt.Errorf("invalid GOARM=%s, must be of form <num>,[hardfloat|softfloat]", options.GOARM)
|
||||
}
|
||||
archLevel := subarch[0]
|
||||
var fpu string
|
||||
if len(subarch) >= 2 {
|
||||
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 {
|
||||
switch options.GOARM {
|
||||
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"
|
||||
}
|
||||
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 "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"
|
||||
}
|
||||
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"
|
||||
}
|
||||
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)
|
||||
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
|
||||
}
|
||||
case "arm64":
|
||||
spec.CPU = "generic"
|
||||
@@ -337,19 +294,19 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
|
||||
}
|
||||
case "mips", "mipsle":
|
||||
spec.CPU = "mips32"
|
||||
spec.CPU = "mips32r2"
|
||||
spec.CFlags = append(spec.CFlags, "-fno-pic")
|
||||
if options.GOARCH == "mips" {
|
||||
if options.GOOS == "mips" {
|
||||
llvmarch = "mips" // big endian
|
||||
} else {
|
||||
llvmarch = "mipsel" // little endian
|
||||
}
|
||||
switch options.GOMIPS {
|
||||
case "hardfloat":
|
||||
spec.Features = "+fpxx,+mips32,+nooddspreg,-noabicalls"
|
||||
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
|
||||
case "softfloat":
|
||||
spec.SoftFloat = true
|
||||
spec.Features = "+mips32,+soft-float,-noabicalls"
|
||||
spec.Features = "+mips32r2,+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)
|
||||
@@ -389,10 +346,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"-arch", llvmarch,
|
||||
"-platform_version", "macos", platformVersion, platformVersion,
|
||||
)
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/os_darwin.c",
|
||||
"src/runtime/runtime_unix.c",
|
||||
"src/runtime/signal.c")
|
||||
case "linux":
|
||||
spec.Linker = "ld.lld"
|
||||
spec.RTLib = "compiler-rt"
|
||||
@@ -412,9 +365,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
// proper threading.
|
||||
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/runtime_unix.c",
|
||||
"src/runtime/signal.c")
|
||||
case "windows":
|
||||
spec.Linker = "ld.lld"
|
||||
spec.Libc = "mingw-w64"
|
||||
@@ -452,7 +402,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"--stack-first",
|
||||
"--no-demangle",
|
||||
)
|
||||
spec.Emulator = "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/asm_tinygowasm.S",
|
||||
"src/internal/task/task_asyncify_wasm.S",
|
||||
@@ -468,15 +418,8 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
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"
|
||||
}
|
||||
} else if options.GOARCH == "arm" {
|
||||
spec.Triple += "-gnueabihf"
|
||||
}
|
||||
|
||||
// Add extra assembly files (needed for the scheduler etc).
|
||||
|
||||
@@ -15,16 +15,6 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
// Return the new value, not the original value returned by atomicrmw.
|
||||
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":
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
|
||||
+23
-8
@@ -70,21 +70,25 @@ func (b *builder) createRuntimeInvoke(fnName string, args []llvm.Value, name str
|
||||
// createCall creates a call to the given function with the arguments possibly
|
||||
// expanded.
|
||||
func (b *builder) createCall(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
|
||||
expanded := make([]llvm.Value, 0, len(args))
|
||||
for _, arg := range args {
|
||||
fragments := b.expandFormalParam(arg)
|
||||
expanded = append(expanded, fragments...)
|
||||
}
|
||||
return b.CreateCall(fnType, fn, expanded, name)
|
||||
return b.CreateCall(fnType, fn, b.expandFormalParams(args), name)
|
||||
}
|
||||
|
||||
// createInvoke is like createCall but continues execution at the landing pad if
|
||||
// the call resulted in a panic.
|
||||
func (b *builder) createInvoke(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
|
||||
if b.hasDeferFrame() {
|
||||
switch b.deferFrameType() {
|
||||
case recoverInlineAsm:
|
||||
b.createInvokeCheckpoint()
|
||||
return b.createCall(fnType, fn, args, name)
|
||||
case recoverWasmEH:
|
||||
continueBB := b.insertBasicBlock("invoke.cont")
|
||||
call := b.CreateInvoke(fnType, fn, b.expandFormalParams(args), continueBB, b.landingpad, name)
|
||||
b.SetInsertPointAtEnd(continueBB)
|
||||
b.blockExits[b.currentBlock] = continueBB
|
||||
return call
|
||||
default:
|
||||
return b.createCall(fnType, fn, args, name)
|
||||
}
|
||||
return b.createCall(fnType, fn, args, name)
|
||||
}
|
||||
|
||||
// Expand an argument type to a list that can be used in a function call
|
||||
@@ -123,6 +127,17 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
|
||||
}
|
||||
}
|
||||
|
||||
// expandFormalParams expands every param in the params slice like
|
||||
// expandFormalParam.
|
||||
func (b *builder) expandFormalParams(params []llvm.Value) []llvm.Value {
|
||||
expanded := make([]llvm.Value, 0, len(params))
|
||||
for _, arg := range params {
|
||||
fragments := b.expandFormalParam(arg)
|
||||
expanded = append(expanded, fragments...)
|
||||
}
|
||||
return expanded
|
||||
}
|
||||
|
||||
// expandFormalParam splits a formal param value into pieces, so it can be
|
||||
// passed directly as part of a function call. For example, it splits up small
|
||||
// structs into individual fields. It is the equivalent of expandFormalParamType
|
||||
|
||||
+15
-25
@@ -44,7 +44,6 @@ type Config struct {
|
||||
ABI string
|
||||
GOOS string
|
||||
GOARCH string
|
||||
BuildMode string
|
||||
CodeModel string
|
||||
RelocationModel string
|
||||
SizeLevel int
|
||||
@@ -356,7 +355,10 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
||||
}
|
||||
|
||||
func (c *compilerContext) getRuntimeType(name string) types.Type {
|
||||
return c.runtimePkg.Scope().Lookup(name).(*types.TypeName).Type()
|
||||
if typ, ok := c.runtimePkg.Scope().Lookup(name).(*types.TypeName); ok {
|
||||
return typ.Type()
|
||||
}
|
||||
panic("runtime type not found: " + name)
|
||||
}
|
||||
|
||||
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
||||
@@ -1351,7 +1353,7 @@ func (b *builder) createFunction() {
|
||||
b.CreateBr(b.afterDefersBlock[i])
|
||||
}
|
||||
|
||||
if b.hasDeferFrame() {
|
||||
if b.deferFrameType() != recoverNone {
|
||||
// Create the landing pad block, where execution continues after a
|
||||
// panic.
|
||||
b.createLandingPad()
|
||||
@@ -1385,11 +1387,6 @@ func (b *builder) createFunction() {
|
||||
b.llvmFn.SetLinkage(llvm.InternalLinkage)
|
||||
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
|
||||
@@ -1493,8 +1490,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
|
||||
b.CreateUnreachable()
|
||||
case *ssa.Return:
|
||||
if b.hasDeferFrame() {
|
||||
b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "")
|
||||
switch b.deferFrameType() {
|
||||
case recoverInlineAsm:
|
||||
b.createRuntimeCall("destroyDeferFrameInlineAsm", []llvm.Value{b.deferFrame}, "")
|
||||
case recoverWasmEH:
|
||||
b.createRuntimeCall("destroyDeferFrameWasmEH", []llvm.Value{b.deferFrame}, "")
|
||||
}
|
||||
if len(instr.Results) == 0 {
|
||||
b.CreateRetVoid()
|
||||
@@ -1747,7 +1747,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
return b.CreateExtractValue(cplx, 0, "real"), nil
|
||||
case "recover":
|
||||
useParentFrame := uint64(0)
|
||||
if b.hasDeferFrame() {
|
||||
if b.fn.Recover != nil {
|
||||
// recover() should return the panic value of the parent function,
|
||||
// not of the current function.
|
||||
useParentFrame = 1
|
||||
@@ -1853,17 +1853,12 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
|
||||
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"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
case name == "runtime.supportsRecover":
|
||||
supportsRecover := uint64(0)
|
||||
if b.supportsRecover() {
|
||||
supportsRecover = 1
|
||||
}
|
||||
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
|
||||
supportsRecover := uint64(b.supportsRecover())
|
||||
return llvm.ConstInt(b.ctx.Int8Type(), supportsRecover, false), nil
|
||||
case name == "runtime.panicStrategy":
|
||||
// These constants are defined in src/runtime/panic.go.
|
||||
panicStrategy := map[string]uint64{
|
||||
@@ -1873,11 +1868,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
|
||||
case name == "runtime/interrupt.New":
|
||||
return b.createInterruptGlobal(instr)
|
||||
case name == "internal/abi.FuncPCABI0":
|
||||
retval := b.createDarwinFuncPCABI0Call(instr)
|
||||
if !retval.IsNil() {
|
||||
return retval, nil
|
||||
}
|
||||
}
|
||||
|
||||
calleeType, callee = b.getFunction(fn)
|
||||
@@ -1976,7 +1966,7 @@ func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
|
||||
return value
|
||||
} else {
|
||||
// indicates a compiler bug
|
||||
panic("SSA value not previously found in function: " + expr.String())
|
||||
panic("local has not been parsed: " + expr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ func TestCompiler(t *testing.T) {
|
||||
{"interface.go", "", ""},
|
||||
{"func.go", "", ""},
|
||||
{"defer.go", "cortex-m-qemu", ""},
|
||||
{"defer.go", "wasm", "none"},
|
||||
{"pragma.go", "", ""},
|
||||
{"goroutine.go", "wasm", "asyncify"},
|
||||
{"goroutine.go", "cortex-m-qemu", "tasks"},
|
||||
|
||||
+137
-41
@@ -23,28 +23,47 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
type recoverType uint8
|
||||
|
||||
const (
|
||||
// Note: this matches recoverSupport in src/runtime/panic.go
|
||||
recoverNone recoverType = iota
|
||||
recoverInlineAsm
|
||||
recoverWasmEH // WebAssembly exception handling
|
||||
)
|
||||
|
||||
// supportsRecover returns whether the compiler supports the recover() builtin
|
||||
// for the current architecture.
|
||||
func (b *builder) supportsRecover() bool {
|
||||
switch b.archFamily() {
|
||||
func (c *compilerContext) supportsRecover() recoverType {
|
||||
switch c.archFamily() {
|
||||
case "wasm32":
|
||||
// Probably needs to be implemented using the exception handling
|
||||
// proposal of WebAssembly:
|
||||
// https://github.com/WebAssembly/exception-handling
|
||||
return false
|
||||
if !strings.Contains(c.Features, "+exception-handling") {
|
||||
// No support for the exception handling proposal.
|
||||
return recoverNone
|
||||
}
|
||||
if c.Scheduler == "asyncify" {
|
||||
// Asyncify does not support WebAssembly exception handling.
|
||||
// It exits with the following message:
|
||||
// unexpected expression type
|
||||
// UNREACHABLE executed at $TINYGOROOT/lib/binaryen/src/passes/Asyncify.cpp:1142!
|
||||
// See: https://github.com/WebAssembly/binaryen/issues/4470
|
||||
return recoverNone
|
||||
}
|
||||
// Use WebAssembly exception handling.
|
||||
return recoverWasmEH
|
||||
case "riscv64", "xtensa":
|
||||
// TODO: add support for these architectures
|
||||
return false
|
||||
return recoverNone
|
||||
default:
|
||||
return true
|
||||
return recoverInlineAsm
|
||||
}
|
||||
}
|
||||
|
||||
// hasDeferFrame returns whether the current function needs to catch panics and
|
||||
// run defers.
|
||||
func (b *builder) hasDeferFrame() bool {
|
||||
// deferFrameType returns the defer type for this function. It is always
|
||||
// recoverNone for functions without defer.
|
||||
func (b *builder) deferFrameType() recoverType {
|
||||
if b.fn.Recover == nil {
|
||||
return false
|
||||
return recoverNone
|
||||
}
|
||||
return b.supportsRecover()
|
||||
}
|
||||
@@ -64,21 +83,40 @@ func (b *builder) deferInitFunc() {
|
||||
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
|
||||
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
|
||||
|
||||
if b.hasDeferFrame() {
|
||||
switch b.deferFrameType() {
|
||||
case recoverInlineAsm:
|
||||
// Set up the defer frame with the current stack pointer.
|
||||
// This assumes that the stack pointer doesn't move outside of the
|
||||
// function prologue/epilogue (an invariant maintained by TinyGo but
|
||||
// possibly broken by the C alloca function).
|
||||
// The frame pointer is _not_ saved, because it is marked as clobbered
|
||||
// in the setjmp-like inline assembly.
|
||||
deferFrameType := b.getLLVMRuntimeType("deferFrame")
|
||||
deferFrameType := b.getLLVMRuntimeType("deferFrameInlineAsm")
|
||||
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
|
||||
stackPointer := b.readStackPointer()
|
||||
b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "")
|
||||
b.createRuntimeCall("setupDeferFrameInlineAsm", []llvm.Value{b.deferFrame, stackPointer}, "")
|
||||
|
||||
// Create the landing pad block, which is where control transfers after
|
||||
// a panic.
|
||||
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad")
|
||||
case recoverWasmEH:
|
||||
// Set a personality function, which is required by LLVM but not
|
||||
// actually called. __gxx_wasm_personality_v0 is the only one that is
|
||||
// acceptable to the WebAssembly backend it seems.
|
||||
personality := b.mod.NamedFunction("__gxx_wasm_personality_v0")
|
||||
if personality.IsNil() {
|
||||
fnType := llvm.FunctionType(b.ctx.Int32Type(), nil, true)
|
||||
personality = llvm.AddFunction(b.mod, "__gxx_wasm_personality_v0", fnType)
|
||||
}
|
||||
b.llvmFn.SetPersonality(personality)
|
||||
|
||||
// Set up the defer frame.
|
||||
deferFrameType := b.getLLVMRuntimeType("deferFrameWasmEH")
|
||||
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
|
||||
b.createRuntimeCall("setupDeferFrameWasmEH", []llvm.Value{b.deferFrame}, "")
|
||||
|
||||
// Create the landing pad where the 'throw' instruction will jump to.
|
||||
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "catch.dispatch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +134,43 @@ func (b *builder) createLandingPad() {
|
||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||
}
|
||||
|
||||
if b.supportsRecover() == recoverWasmEH {
|
||||
// Insert exception handling instructions.
|
||||
// This emulates C++ exceptions, as if every function is wrapped like
|
||||
// this:
|
||||
//
|
||||
// try {
|
||||
// function body
|
||||
// } catch (...) {
|
||||
// run all defers
|
||||
// }
|
||||
// if deferFrame.Panicking {
|
||||
// // re-raise the same panic message
|
||||
// panic(previousPanic)
|
||||
// }
|
||||
//
|
||||
// This means that if there is a C++ exception in the program, it will
|
||||
// get eaten by the Go code. This is fixable if needed (by checking
|
||||
// whether it's actually a TinyGo exception and re-raising the same
|
||||
// exception if it isn't after running deferred functions).
|
||||
// For more information about C++ exception support in WebAssembly:
|
||||
// https://github.com/WebAssembly/tool-conventions/blob/main/EHScheme.md
|
||||
|
||||
// basic block: catch.dispatch
|
||||
catchStartBB := b.insertBasicBlock("catch.start")
|
||||
catchswitch := b.CreateCatchSwitch(llvm.Value{}, llvm.BasicBlock{}, 1, "")
|
||||
catchswitch.AddHandler(catchStartBB)
|
||||
|
||||
// basic block: catch.start
|
||||
b.SetInsertPointAtEnd(catchStartBB)
|
||||
catchpad := b.CreateCatchPad(catchswitch, []llvm.Value{llvm.ConstNull(b.dataPtrType)}, "")
|
||||
rundefersBB := b.insertBasicBlock("rundefers")
|
||||
b.CreateCatchRet(catchpad, rundefersBB)
|
||||
|
||||
// basic block: rundefers
|
||||
b.SetInsertPointAtEnd(rundefersBB)
|
||||
}
|
||||
|
||||
b.createRunDefers()
|
||||
|
||||
// Continue at the 'recover' block, which returns to the parent in an
|
||||
@@ -199,13 +274,7 @@ jal 1f
|
||||
addiu $$ra, 8
|
||||
sw $$ra, 4($$5)
|
||||
.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}"
|
||||
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}"
|
||||
}
|
||||
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}"
|
||||
case "riscv32":
|
||||
asmString = `
|
||||
la a2, 1f
|
||||
@@ -439,11 +508,25 @@ func (b *builder) createRunDefers() {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end.
|
||||
// Create loop, in the order:
|
||||
// - loophead
|
||||
// - loop
|
||||
// - callback0
|
||||
// - callback1
|
||||
// - callback*
|
||||
// - unreachable
|
||||
// - catch.dispatch (if wasm EH)
|
||||
// - catch.start (if wasm EH)
|
||||
// - end
|
||||
var catchDispatch, catchStart llvm.BasicBlock
|
||||
end := b.insertBasicBlock("rundefers.end")
|
||||
unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default")
|
||||
loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop")
|
||||
loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead")
|
||||
if b.supportsRecover() == recoverWasmEH {
|
||||
catchDispatch = b.ctx.InsertBasicBlock(end, "rundefers.catch.dispatch")
|
||||
catchStart = b.ctx.InsertBasicBlock(end, "rundefers.catch.start")
|
||||
}
|
||||
b.CreateBr(loophead)
|
||||
|
||||
// Create loop head:
|
||||
@@ -478,6 +561,9 @@ func (b *builder) createRunDefers() {
|
||||
block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i))
|
||||
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
|
||||
b.SetInsertPointAtEnd(block)
|
||||
var fnType llvm.Type
|
||||
var llvmFn llvm.Value
|
||||
var forwardParams []llvm.Value
|
||||
switch callback := callback.(type) {
|
||||
case *ssa.CallCommon:
|
||||
// Call on an value or interface value.
|
||||
@@ -498,7 +584,6 @@ func (b *builder) createRunDefers() {
|
||||
}
|
||||
|
||||
// Extract the params from the struct (including receiver).
|
||||
forwardParams := []llvm.Value{}
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||
for i := 2; i < len(valueTypes); i++ {
|
||||
@@ -507,9 +592,6 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, forwardParam)
|
||||
}
|
||||
|
||||
var fnPtr llvm.Value
|
||||
var fnType llvm.Type
|
||||
|
||||
if !callback.IsInvoke() {
|
||||
// Isolate the func value.
|
||||
funcValue := forwardParams[0]
|
||||
@@ -517,7 +599,7 @@ func (b *builder) createRunDefers() {
|
||||
|
||||
//Get function pointer and context
|
||||
var context llvm.Value
|
||||
fnPtr, context = b.decodeFuncValue(funcValue)
|
||||
llvmFn, context = b.decodeFuncValue(funcValue)
|
||||
fnType = b.getLLVMFunctionType(callback.Signature())
|
||||
|
||||
//Pass context
|
||||
@@ -526,8 +608,8 @@ func (b *builder) createRunDefers() {
|
||||
// Move typecode from the start to the end of the list of
|
||||
// parameters.
|
||||
forwardParams = append(forwardParams[1:], forwardParams[0])
|
||||
fnPtr = b.getInvokeFunction(callback)
|
||||
fnType = fnPtr.GlobalValueType()
|
||||
llvmFn = b.getInvokeFunction(callback)
|
||||
fnType = llvmFn.GlobalValueType()
|
||||
|
||||
// Add the context parameter. An interface call cannot also be a
|
||||
// closure but we have to supply the parameter anyway for platforms
|
||||
@@ -535,8 +617,6 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
|
||||
}
|
||||
|
||||
b.createCall(fnType, fnPtr, forwardParams, "")
|
||||
|
||||
case *ssa.Function:
|
||||
// Direct call.
|
||||
|
||||
@@ -548,7 +628,6 @@ func (b *builder) createRunDefers() {
|
||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||
|
||||
// Extract the params from the struct.
|
||||
forwardParams := []llvm.Value{}
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := range getParams(callback.Signature) {
|
||||
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||
@@ -564,9 +643,7 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
|
||||
}
|
||||
|
||||
// Call real function.
|
||||
fnType, fn := b.getFunction(callback)
|
||||
b.createInvoke(fnType, fn, forwardParams, "")
|
||||
fnType, llvmFn = b.getFunction(callback)
|
||||
|
||||
case *ssa.MakeClosure:
|
||||
// Get the real defer struct type and cast to it.
|
||||
@@ -580,7 +657,6 @@ func (b *builder) createRunDefers() {
|
||||
deferredCallType := b.ctx.StructType(valueTypes, false)
|
||||
|
||||
// Extract the params from the struct.
|
||||
forwardParams := []llvm.Value{}
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 2; i < len(valueTypes); i++ {
|
||||
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
||||
@@ -589,8 +665,7 @@ func (b *builder) createRunDefers() {
|
||||
}
|
||||
|
||||
// Call deferred function.
|
||||
fnType, llvmFn := b.getFunction(fn)
|
||||
b.createCall(fnType, llvmFn, forwardParams, "")
|
||||
fnType, llvmFn = b.getFunction(fn)
|
||||
case *ssa.Builtin:
|
||||
db := b.deferBuiltinFuncs[callback]
|
||||
|
||||
@@ -618,12 +693,20 @@ func (b *builder) createRunDefers() {
|
||||
if err != nil {
|
||||
b.diagnostics = append(b.diagnostics, err)
|
||||
}
|
||||
b.CreateBr(loophead)
|
||||
continue
|
||||
default:
|
||||
panic("unknown deferred function type")
|
||||
}
|
||||
|
||||
// Branch back to the start of the loop.
|
||||
b.CreateBr(loophead)
|
||||
// Call the deferred function.
|
||||
if b.supportsRecover() == recoverWasmEH {
|
||||
b.CreateInvoke(fnType, llvmFn, b.expandFormalParams(forwardParams), loophead, catchDispatch, "")
|
||||
} else {
|
||||
b.createInvoke(fnType, llvmFn, forwardParams, "")
|
||||
// Branch back to the start of the loop.
|
||||
b.CreateBr(loophead)
|
||||
}
|
||||
}
|
||||
|
||||
// Create default unreachable block:
|
||||
@@ -633,6 +716,19 @@ func (b *builder) createRunDefers() {
|
||||
b.SetInsertPointAtEnd(unreachable)
|
||||
b.CreateUnreachable()
|
||||
|
||||
// Ignore any exception that might have occured while running the deferred
|
||||
// functions. The compiler will insert a check whether the function is still
|
||||
// panicking before return, so no panic gets lost.
|
||||
if b.supportsRecover() == recoverWasmEH {
|
||||
b.SetInsertPointAtEnd(catchDispatch)
|
||||
catchswitch := b.CreateCatchSwitch(llvm.Value{}, llvm.BasicBlock{}, 1, "")
|
||||
catchswitch.AddHandler(catchStart)
|
||||
|
||||
b.SetInsertPointAtEnd(catchStart)
|
||||
catchpad := b.CreateCatchPad(catchswitch, []llvm.Value{llvm.ConstNull(b.dataPtrType)}, "")
|
||||
b.CreateCatchRet(catchpad, loophead)
|
||||
}
|
||||
|
||||
// End of loop.
|
||||
b.SetInsertPointAtEnd(end)
|
||||
}
|
||||
|
||||
+51
-286
@@ -7,14 +7,43 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// createGo emits code to start a new goroutine.
|
||||
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 might as well run these builtins right away without the program
|
||||
// noticing the difference.
|
||||
@@ -45,38 +74,6 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
}
|
||||
b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos())
|
||||
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() {
|
||||
// This is a method call on an interface value.
|
||||
itf := b.getValue(instr.Call.Value, getPos(instr))
|
||||
@@ -102,7 +99,7 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
|
||||
paramBundle := b.emitPointerPack(params)
|
||||
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 {
|
||||
// The stack size is not known until after linking. Call a dummy
|
||||
// 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)}, "")
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// false, the parameter bundle is assumed to have no context parameter and undef
|
||||
// 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
|
||||
|
||||
b := &builder{
|
||||
@@ -304,18 +160,14 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
|
||||
if !fn.IsAFunction().IsNil() {
|
||||
// See whether this wrapper has already been created. If so, return it.
|
||||
name := fn.Name()
|
||||
wrapperName := name + "$gowrapper"
|
||||
if isWasmExport {
|
||||
wrapperName += "-wasmexport"
|
||||
}
|
||||
wrapper = c.mod.NamedFunction(wrapperName)
|
||||
wrapper = c.mod.NamedFunction(name + "$gowrapper")
|
||||
if !wrapper.IsNil() {
|
||||
return llvm.ConstPtrToInt(wrapper, c.uintptrType)
|
||||
}
|
||||
|
||||
// Create the wrapper.
|
||||
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)
|
||||
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
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{})
|
||||
}
|
||||
|
||||
if !isWasmExport {
|
||||
// Regular 'go' instruction.
|
||||
// Create the list of params for the call.
|
||||
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.
|
||||
paramTypes := fnType.ParamTypes()
|
||||
if !hasContext {
|
||||
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
|
||||
}
|
||||
// Create the call.
|
||||
b.CreateCall(fnType, fn, params, "")
|
||||
|
||||
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
|
||||
if !hasContext {
|
||||
params = append(params, llvm.Undef(c.dataPtrType)) // add dummy context parameter
|
||||
}
|
||||
|
||||
// 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, "")
|
||||
if c.Scheduler == "asyncify" {
|
||||
b.CreateCall(deadlockType, deadlock, []llvm.Value{
|
||||
llvm.Undef(c.dataPtrType),
|
||||
}, "")
|
||||
}
|
||||
|
||||
} 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 llvm.ConstPtrToInt(wrapper, c.uintptrType)
|
||||
return b.CreatePtrToInt(wrapper, c.uintptrType, "")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package llvmutil
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -217,13 +216,3 @@ func Version() int {
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+110
-188
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
@@ -24,17 +23,15 @@ import (
|
||||
// The linkName value contains a valid link name, even if //go:linkname is not
|
||||
// present.
|
||||
type functionInfo struct {
|
||||
wasmModule string // go:wasm-module
|
||||
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)
|
||||
wasmExportPos token.Pos // position of //go:wasmexport comment
|
||||
linkName string // go:linkname, go:export - the IR function name
|
||||
section string // go:section - object file section name
|
||||
exported bool // go:export, CGo
|
||||
interrupt bool // go:interrupt
|
||||
nobounds bool // go:nobounds
|
||||
variadic bool // go:variadic (CGo only)
|
||||
inline inlineType // go:inline
|
||||
wasmModule string // go:wasm-module
|
||||
wasmName string // wasm-export-name or wasm-import-name in the IR
|
||||
linkName string // go:linkname, go:export - the IR function name
|
||||
section string // go:section - object file section name
|
||||
exported bool // go:export, CGo
|
||||
interrupt bool // go:interrupt
|
||||
nobounds bool // go:nobounds
|
||||
variadic bool // go:variadic (CGo only)
|
||||
inline inlineType // go:inline
|
||||
}
|
||||
|
||||
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.
|
||||
// Mark it as noreturn so LLVM can optimize away code.
|
||||
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":
|
||||
// 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.
|
||||
@@ -173,18 +168,13 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
case "runtime.stringFromBytes":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
case "runtime.stringFromRunes":
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
case "runtime.trackPointer":
|
||||
// This function is necessary for tracking pointers on the stack in a
|
||||
// portable way (see gc_stack_portable.go). Indicate to the optimizer
|
||||
// that the only thing we'll do is read the pointer.
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
|
||||
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
|
||||
case "__mulsi3", "__divmodsi4", "__udivmodsi4":
|
||||
if strings.Split(c.Triple, "-")[0] == "avr" {
|
||||
// These functions are compiler-rt/libgcc functions that are
|
||||
@@ -227,7 +217,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// should be created right away.
|
||||
// The exception is the package initializer, which does appear in the
|
||||
// *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()
|
||||
b := newBuilder(c, irbuilder, fn)
|
||||
b.createFunction()
|
||||
@@ -250,22 +240,8 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
// Pick the default linkName.
|
||||
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).
|
||||
c.parsePragmas(&info, f)
|
||||
|
||||
c.functionInfos[f] = info
|
||||
return info
|
||||
}
|
||||
@@ -273,164 +249,126 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
|
||||
// //export or //go:noinline.
|
||||
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
syntax := f.Syntax()
|
||||
if f.Origin() != nil {
|
||||
syntax = f.Origin().Syntax()
|
||||
}
|
||||
if syntax == nil {
|
||||
if f.Syntax() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Read all pragmas of this function.
|
||||
var pragmas []*ast.Comment
|
||||
hasWasmExport := false
|
||||
if decl, ok := syntax.(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||
for _, comment := range decl.Doc.List {
|
||||
text := comment.Text
|
||||
if strings.HasPrefix(text, "//go:") || strings.HasPrefix(text, "//export ") {
|
||||
pragmas = append(pragmas, comment)
|
||||
if strings.HasPrefix(comment.Text, "//go:wasmexport ") {
|
||||
hasWasmExport = true
|
||||
if strings.HasPrefix(text, "//export ") {
|
||||
// Rewrite '//export' to '//go:export' for compatibility with
|
||||
// gc.
|
||||
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.
|
||||
for _, comment := range pragmas {
|
||||
parts := strings.Fields(comment.Text)
|
||||
switch parts[0] {
|
||||
case "//export", "//go:export":
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
if hasWasmExport {
|
||||
// //go:wasmexport overrides //export.
|
||||
continue
|
||||
}
|
||||
|
||||
info.linkName = parts[1]
|
||||
info.wasmName = info.linkName
|
||||
info.exported = true
|
||||
case "//go:interrupt":
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.interrupt = true
|
||||
}
|
||||
case "//go:wasm-module":
|
||||
// Alternative comment for setting the import module.
|
||||
// This is deprecated, use //go:wasmimport instead.
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
info.wasmModule = parts[1]
|
||||
case "//go:wasmimport":
|
||||
// Import a WebAssembly function, for example a WASI function.
|
||||
// Original proposal: https://github.com/golang/go/issues/38248
|
||||
// Allow globally: https://github.com/golang/go/issues/59149
|
||||
if len(parts) != 3 {
|
||||
continue
|
||||
}
|
||||
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.linkName = parts[1]
|
||||
info.wasmName = info.linkName
|
||||
info.exported = true
|
||||
case "//go:interrupt":
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.interrupt = true
|
||||
}
|
||||
case "//go:wasm-module":
|
||||
// Alternative comment for setting the import module.
|
||||
// This is deprecated, use //go:wasmimport instead.
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
info.wasmModule = parts[1]
|
||||
case "//go:wasmimport":
|
||||
// Import a WebAssembly function, for example a WASI function.
|
||||
// Original proposal: https://github.com/golang/go/issues/38248
|
||||
// Allow globally: https://github.com/golang/go/issues/59149
|
||||
if len(parts) != 3 {
|
||||
continue
|
||||
}
|
||||
c.checkWasmImport(f, comment.Text)
|
||||
info.exported = true
|
||||
info.wasmModule = parts[1]
|
||||
info.wasmName = parts[2]
|
||||
case "//go:inline":
|
||||
info.inline = inlineHint
|
||||
case "//go:noinline":
|
||||
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
|
||||
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
|
||||
}
|
||||
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
|
||||
// //go:wasmexport. It will add an error if this is not the case.
|
||||
// Check whether this function cannot be used in //go:wasmimport. It will add an
|
||||
// error if this is the case.
|
||||
//
|
||||
// The list of allowed types is based on this proposal:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func (c *compilerContext) 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" {
|
||||
// The runtime is a special case. Allow all kinds of parameters
|
||||
// (importantly, including pointers).
|
||||
return
|
||||
}
|
||||
if f.Blocks != nil {
|
||||
// Defined functions cannot be exported.
|
||||
c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
|
||||
return
|
||||
}
|
||||
if f.Signature.Results().Len() > 1 {
|
||||
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
|
||||
} else if f.Signature.Results().Len() == 1 {
|
||||
result := f.Signature.Results().At(0)
|
||||
if !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()))
|
||||
}
|
||||
}
|
||||
for _, param := range f.Params {
|
||||
// Check whether the type is allowed.
|
||||
// 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()))
|
||||
}
|
||||
}
|
||||
@@ -443,15 +381,13 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
|
||||
//
|
||||
// This previously reflected the additional restrictions documented here:
|
||||
// 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) {
|
||||
case *types.Basic:
|
||||
switch typ.Kind() {
|
||||
case types.Bool:
|
||||
return true
|
||||
case types.Int8, types.Uint8, types.Int16, types.Uint16:
|
||||
return site == siteIndirect
|
||||
case types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
case types.Int, types.Uint, types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
return true
|
||||
case types.Float32, types.Float64:
|
||||
return true
|
||||
@@ -462,35 +398,19 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
|
||||
return site == siteParam || site == siteIndirect
|
||||
}
|
||||
case *types.Array:
|
||||
return site == siteIndirect && c.isValidWasmType(typ.Elem(), siteIndirect)
|
||||
return site == siteIndirect && isValidWasmType(typ.Elem(), siteIndirect)
|
||||
case *types.Struct:
|
||||
if site != siteIndirect {
|
||||
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++ {
|
||||
ftyp := typ.Field(i).Type()
|
||||
if ftyp.String() == "structs.HostLayout" {
|
||||
hasHostLayout = true
|
||||
continue
|
||||
}
|
||||
if !c.isValidWasmType(ftyp, siteIndirect) {
|
||||
if !isValidWasmType(typ.Field(i).Type(), siteIndirect) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return hasHostLayout
|
||||
return true
|
||||
case *types.Pointer:
|
||||
return c.isValidWasmType(typ.Elem(), siteIndirect)
|
||||
return isValidWasmType(typ.Elem(), siteIndirect)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -551,7 +471,9 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
|
||||
// This behavior matches Clang when compiling C source files.
|
||||
// It reduces binary size on Linux a little bit on non-x86_64 targets by
|
||||
// eliminating exception tables for these functions.
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
|
||||
if c.supportsRecover() != recoverWasmEH {
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
|
||||
}
|
||||
if strings.Split(c.Triple, "-")[0] == "x86_64" {
|
||||
// Required by the ABI.
|
||||
// The uwtable has two possible values: sync (1) or async (2). We use
|
||||
|
||||
@@ -5,7 +5,6 @@ package compiler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
@@ -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, "")
|
||||
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, "")
|
||||
}
|
||||
|
||||
Vendored
+25
-24
@@ -13,30 +13,31 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = add i32 %x, %y
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -54,10 +55,10 @@ divbyzero.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.divideByZeroPanic(ptr) #1
|
||||
declare void @runtime.divideByZeroPanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -72,7 +73,7 @@ divbyzero.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -91,7 +92,7 @@ divbyzero.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
@@ -106,61 +107,61 @@ divbyzero.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp oeq float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp une float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp olt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp ole float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp oge float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret float %x.r
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret float %x.i
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fadd float %x.r, %y.r
|
||||
%1 = fadd float %x.i, %y.i
|
||||
@@ -170,7 +171,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fsub float %x.r, %y.r
|
||||
%1 = fsub float %x.i, %y.i
|
||||
@@ -180,7 +181,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fmul float %x.r, %y.r
|
||||
%1 = fmul float %x.i, %y.i
|
||||
@@ -194,19 +195,19 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.foo(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+16
-15
@@ -9,16 +9,17 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
@@ -32,15 +33,15 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
|
||||
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
|
||||
declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #3
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
@@ -52,10 +53,10 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1
|
||||
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
@@ -65,7 +66,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
|
||||
@@ -75,7 +76,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
||||
%select.send.value = alloca i32, align 4
|
||||
@@ -105,10 +106,10 @@ select.body: ; preds = %select.next
|
||||
br label %select.done
|
||||
}
|
||||
|
||||
declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #1
|
||||
declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #3
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
+11
-11
@@ -3,7 +3,7 @@ source_filename = "defer.go"
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i1, %runtime._interface }
|
||||
%runtime.deferFrameInlineAsm = type { ptr, ptr, [0 x ptr], ptr, i1, %runtime._interface }
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
%runtime._defer = type { i32, ptr }
|
||||
|
||||
@@ -24,9 +24,9 @@ entry:
|
||||
%defer.alloca = alloca { i32, ptr }, align 4
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrameInlineAsm, align 4
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
call void @runtime.setupDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
store ptr null, ptr %defer.alloca.repack15, align 4
|
||||
@@ -40,7 +40,7 @@ entry:
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %1
|
||||
@@ -76,7 +76,7 @@ rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end3
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
lpad: ; preds = %rundefers.callback012, %rundefers.callback0, %entry
|
||||
@@ -115,9 +115,9 @@ rundefers.end3: ; preds = %rundefers.loophead6
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
||||
declare ptr @llvm.stacksave.p0() #3
|
||||
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
declare void @runtime.setupDeferFrameInlineAsm(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
|
||||
declare void @runtime.destroyDeferFrameInlineAsm(ptr dereferenceable_or_null(24), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
|
||||
@@ -135,9 +135,9 @@ entry:
|
||||
%defer.alloca = alloca { i32, ptr }, align 4
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrameInlineAsm, align 4
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
call void @runtime.setupDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
store ptr null, ptr %defer.alloca.repack22, align 4
|
||||
@@ -155,7 +155,7 @@ entry:
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %1
|
||||
@@ -201,7 +201,7 @@ rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end7
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
lpad: ; preds = %rundefers.callback119, %rundefers.callback016, %rundefers.callback1, %rundefers.callback0, %entry
|
||||
|
||||
Vendored
+273
@@ -0,0 +1,273 @@
|
||||
; ModuleID = 'defer.go'
|
||||
source_filename = "defer.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.deferFrameWasmEH = type { ptr, i1, %runtime._interface }
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
%runtime._defer = type { i32, ptr }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.external(ptr) #2
|
||||
|
||||
define hidden void @main.deferSimple(ptr %context) unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 {
|
||||
entry:
|
||||
%defer.alloca = alloca { i32, ptr }, align 8
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrameWasmEH, align 8
|
||||
call void @runtime.setupDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull %defer.alloca, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack13 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
store ptr null, ptr %defer.alloca.repack13, align 4
|
||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||
invoke void @main.external(ptr undef)
|
||||
to label %invoke.cont unwind label %catch.dispatch
|
||||
|
||||
invoke.cont: ; preds = %entry
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %invoke.cont
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %rundefers.catch.start, %rundefers.callback0, %rundefers.block
|
||||
%0 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %0, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds %runtime._defer, ptr %0, i32 0, i32 1
|
||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||
store ptr %stack.next, ptr %deferPtr, align 4
|
||||
%callback = load i32, ptr %0, align 4
|
||||
switch i32 %callback, label %rundefers.default [
|
||||
i32 0, label %rundefers.callback0
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
invoke void @"main.deferSimple$1"(ptr undef)
|
||||
to label %rundefers.loophead unwind label %rundefers.catch.dispatch
|
||||
|
||||
rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.catch.dispatch: ; preds = %rundefers.callback0
|
||||
%1 = catchswitch within none [label %rundefers.catch.start] unwind to caller
|
||||
|
||||
rundefers.catch.start: ; preds = %rundefers.catch.dispatch
|
||||
%2 = catchpad within %1 [ptr null]
|
||||
catchret from %2 to label %rundefers.loophead
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end1
|
||||
call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
ret void
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%3 = catchswitch within none [label %catch.start] unwind to caller
|
||||
|
||||
catch.start: ; preds = %catch.dispatch
|
||||
%4 = catchpad within %3 [ptr null]
|
||||
catchret from %4 to label %rundefers
|
||||
|
||||
rundefers: ; preds = %catch.start
|
||||
br label %rundefers.loophead4
|
||||
|
||||
rundefers.loophead4: ; preds = %rundefers.catch.start6, %rundefers.callback012, %rundefers
|
||||
%5 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil7 = icmp eq ptr %5, null
|
||||
br i1 %stackIsNil7, label %rundefers.end1, label %rundefers.loop3
|
||||
|
||||
rundefers.loop3: ; preds = %rundefers.loophead4
|
||||
%stack.next.gep8 = getelementptr inbounds %runtime._defer, ptr %5, i32 0, i32 1
|
||||
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4
|
||||
store ptr %stack.next9, ptr %deferPtr, align 4
|
||||
%callback11 = load i32, ptr %5, align 4
|
||||
switch i32 %callback11, label %rundefers.default2 [
|
||||
i32 0, label %rundefers.callback012
|
||||
]
|
||||
|
||||
rundefers.callback012: ; preds = %rundefers.loop3
|
||||
invoke void @"main.deferSimple$1"(ptr undef)
|
||||
to label %rundefers.loophead4 unwind label %rundefers.catch.dispatch5
|
||||
|
||||
rundefers.default2: ; preds = %rundefers.loop3
|
||||
unreachable
|
||||
|
||||
rundefers.catch.dispatch5: ; preds = %rundefers.callback012
|
||||
%6 = catchswitch within none [label %rundefers.catch.start6] unwind to caller
|
||||
|
||||
rundefers.catch.start6: ; preds = %rundefers.catch.dispatch5
|
||||
%7 = catchpad within %6 [ptr null]
|
||||
catchret from %7 to label %rundefers.loophead4
|
||||
|
||||
rundefers.end1: ; preds = %rundefers.loophead4
|
||||
br label %recover
|
||||
}
|
||||
|
||||
declare i32 @__gxx_wasm_personality_v0(...)
|
||||
|
||||
declare void @runtime.setupDeferFrameWasmEH(ptr dereferenceable_or_null(16), ptr) #2
|
||||
|
||||
declare void @runtime.destroyDeferFrameWasmEH(ptr dereferenceable_or_null(16), ptr) #2
|
||||
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
|
||||
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 {
|
||||
entry:
|
||||
%defer.alloca2 = alloca { i32, ptr }, align 8
|
||||
%defer.alloca = alloca { i32, ptr }, align 8
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrameWasmEH, align 8
|
||||
call void @runtime.setupDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull %defer.alloca, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack16 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
store ptr null, ptr %defer.alloca.repack16, align 4
|
||||
store ptr %defer.alloca, ptr %deferPtr, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %defer.alloca2, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 1, ptr %defer.alloca2, align 4
|
||||
%defer.alloca2.repack17 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca2, i32 0, i32 1
|
||||
store ptr %defer.alloca, ptr %defer.alloca2.repack17, align 4
|
||||
store ptr %defer.alloca2, ptr %deferPtr, align 4
|
||||
invoke void @main.external(ptr undef)
|
||||
to label %invoke.cont unwind label %catch.dispatch
|
||||
|
||||
invoke.cont: ; preds = %entry
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %invoke.cont
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %rundefers.catch.start, %rundefers.callback1, %rundefers.callback0, %rundefers.block
|
||||
%0 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %0, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
|
||||
rundefers.loop: ; preds = %rundefers.loophead
|
||||
%stack.next.gep = getelementptr inbounds %runtime._defer, ptr %0, i32 0, i32 1
|
||||
%stack.next = load ptr, ptr %stack.next.gep, align 4
|
||||
store ptr %stack.next, ptr %deferPtr, align 4
|
||||
%callback = load i32, ptr %0, align 4
|
||||
switch i32 %callback, label %rundefers.default [
|
||||
i32 0, label %rundefers.callback0
|
||||
i32 1, label %rundefers.callback1
|
||||
]
|
||||
|
||||
rundefers.callback0: ; preds = %rundefers.loop
|
||||
invoke void @"main.deferMultiple$1"(ptr undef)
|
||||
to label %rundefers.loophead unwind label %rundefers.catch.dispatch
|
||||
|
||||
rundefers.callback1: ; preds = %rundefers.loop
|
||||
invoke void @"main.deferMultiple$2"(ptr undef)
|
||||
to label %rundefers.loophead unwind label %rundefers.catch.dispatch
|
||||
|
||||
rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.catch.dispatch: ; preds = %rundefers.callback1, %rundefers.callback0
|
||||
%1 = catchswitch within none [label %rundefers.catch.start] unwind to caller
|
||||
|
||||
rundefers.catch.start: ; preds = %rundefers.catch.dispatch
|
||||
%2 = catchpad within %1 [ptr null]
|
||||
catchret from %2 to label %rundefers.loophead
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
|
||||
recover: ; preds = %rundefers.end3
|
||||
call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef)
|
||||
ret void
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%3 = catchswitch within none [label %catch.start] unwind to caller
|
||||
|
||||
catch.start: ; preds = %catch.dispatch
|
||||
%4 = catchpad within %3 [ptr null]
|
||||
catchret from %4 to label %rundefers
|
||||
|
||||
rundefers: ; preds = %catch.start
|
||||
br label %rundefers.loophead6
|
||||
|
||||
rundefers.loophead6: ; preds = %rundefers.catch.start8, %rundefers.callback115, %rundefers.callback014, %rundefers
|
||||
%5 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil9 = icmp eq ptr %5, null
|
||||
br i1 %stackIsNil9, label %rundefers.end3, label %rundefers.loop5
|
||||
|
||||
rundefers.loop5: ; preds = %rundefers.loophead6
|
||||
%stack.next.gep10 = getelementptr inbounds %runtime._defer, ptr %5, i32 0, i32 1
|
||||
%stack.next11 = load ptr, ptr %stack.next.gep10, align 4
|
||||
store ptr %stack.next11, ptr %deferPtr, align 4
|
||||
%callback13 = load i32, ptr %5, align 4
|
||||
switch i32 %callback13, label %rundefers.default4 [
|
||||
i32 0, label %rundefers.callback014
|
||||
i32 1, label %rundefers.callback115
|
||||
]
|
||||
|
||||
rundefers.callback014: ; preds = %rundefers.loop5
|
||||
invoke void @"main.deferMultiple$1"(ptr undef)
|
||||
to label %rundefers.loophead6 unwind label %rundefers.catch.dispatch7
|
||||
|
||||
rundefers.callback115: ; preds = %rundefers.loop5
|
||||
invoke void @"main.deferMultiple$2"(ptr undef)
|
||||
to label %rundefers.loophead6 unwind label %rundefers.catch.dispatch7
|
||||
|
||||
rundefers.default4: ; preds = %rundefers.loop5
|
||||
unreachable
|
||||
|
||||
rundefers.catch.dispatch7: ; preds = %rundefers.callback115, %rundefers.callback014
|
||||
%6 = catchswitch within none [label %rundefers.catch.start8] unwind to caller
|
||||
|
||||
rundefers.catch.start8: ; preds = %rundefers.catch.dispatch7
|
||||
%7 = catchpad within %6 [ptr null]
|
||||
catchret from %7 to label %rundefers.loophead6
|
||||
|
||||
rundefers.end3: ; preds = %rundefers.loophead6
|
||||
br label %recover
|
||||
}
|
||||
|
||||
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 5, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
Vendored
+7
-37
@@ -1,9 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"structs"
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
//go:wasmimport modulename empty
|
||||
func empty()
|
||||
@@ -17,37 +14,31 @@ func implementation() {
|
||||
type Uint uint32
|
||||
|
||||
type S struct {
|
||||
_ structs.HostLayout
|
||||
a [4]uint32
|
||||
b uintptr
|
||||
c int
|
||||
d float32
|
||||
e float64
|
||||
}
|
||||
|
||||
//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 []byte
|
||||
// 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 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
|
||||
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func(), f int, g uint, h [8]int)
|
||||
|
||||
// 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 })
|
||||
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func())
|
||||
|
||||
//go:wasmimport modulename validreturn_int32
|
||||
func validreturn_int32() int32
|
||||
|
||||
//go:wasmimport modulename validreturn_int
|
||||
func validreturn_int() int
|
||||
|
||||
//go:wasmimport modulename validreturn_ptr_int32
|
||||
func validreturn_ptr_int32() *int32
|
||||
|
||||
@@ -57,12 +48,6 @@ func validreturn_ptr_string() *string
|
||||
//go:wasmimport modulename validreturn_ptr_struct
|
||||
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
|
||||
func validreturn_unsafe_pointer() unsafe.Pointer
|
||||
|
||||
@@ -71,26 +56,11 @@ func validreturn_unsafe_pointer() unsafe.Pointer
|
||||
//go:wasmimport modulename manyreturns
|
||||
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()
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn_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
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn_slice_byte
|
||||
|
||||
Vendored
+12
-12
@@ -6,16 +6,17 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -27,25 +28,25 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret float 0x41F0000000000000
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 -1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 {
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = uitofp i32 %v to float
|
||||
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
||||
@@ -55,7 +56,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -68,7 +69,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 2.550000e+02
|
||||
@@ -80,7 +81,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%abovemin = fcmp oge float %v, -1.280000e+02
|
||||
%belowmax = fcmp ole float %v, 1.270000e+02
|
||||
@@ -93,6 +94,5 @@ entry:
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
|
||||
Vendored
+9
-8
@@ -6,16 +6,17 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp eq ptr %callback.funcptr, null
|
||||
br i1 %0, label %fpcall.throw, label %fpcall.next
|
||||
@@ -29,22 +30,22 @@ fpcall.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.nilPanic(ptr) #1
|
||||
declare void @runtime.nilPanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.bar(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+45
-45
@@ -27,93 +27,94 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new, ptr @main.scalar1, align 4
|
||||
%new1 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new1 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new1, ptr @main.scalar2, align 4
|
||||
%new2 = call align 8 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new2 = call align 8 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new2, ptr @main.scalar3, align 4
|
||||
%new3 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new3, ptr @main.scalar4, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new, ptr @main.array1, align 4
|
||||
%new1 = call align 1 dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new1 = call align 1 dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new1, ptr @main.array2, align 4
|
||||
%new2 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new2, ptr @main.array3, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new, ptr @main.struct1, align 4
|
||||
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new1, ptr @main.struct2, align 4
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new2, ptr @main.struct3, align 4
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %new3, ptr @main.struct4, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %new
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %makeslice, ptr @main.slice1, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 4
|
||||
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %makeslice1, ptr @main.slice2, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 4
|
||||
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef)
|
||||
store ptr %makeslice3, ptr @main.slice3, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 4
|
||||
@@ -121,21 +122,20 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #2
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef)
|
||||
store double %v.r, ptr %0, align 8
|
||||
%.repack1 = getelementptr inbounds { double, double }, ptr %0, i32 0, i32 1
|
||||
store double %v.i, ptr %.repack1, align 8
|
||||
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._interface %1
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
Vendored
+12
-11
@@ -8,24 +8,25 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %s.data
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp slt i16 %len, 0
|
||||
@@ -39,7 +40,7 @@ unsafe.String.next: ; preds = %entry
|
||||
%5 = zext i16 %len to i32
|
||||
%6 = insertvalue %runtime._string undef, ptr %ptr, 0
|
||||
%7 = insertvalue %runtime._string %6, i32 %5, 1
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._string %7
|
||||
|
||||
unsafe.String.throw: ; preds = %entry
|
||||
@@ -47,17 +48,17 @@ unsafe.String.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %s.data
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+25
-24
@@ -8,29 +8,30 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
@@ -38,7 +39,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
@@ -47,21 +48,21 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp olt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
@@ -69,7 +70,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp olt double %a, %b
|
||||
%1 = select i1 %0, double %a, double %b
|
||||
@@ -77,7 +78,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
@@ -87,28 +88,28 @@ entry:
|
||||
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = extractvalue %runtime._string %5, 0
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
@@ -116,7 +117,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
@@ -126,12 +127,12 @@ entry:
|
||||
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = extractvalue %runtime._string %5, 0
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = shl i32 %s.len, 2
|
||||
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
|
||||
@@ -142,19 +143,19 @@ entry:
|
||||
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #2
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.smin.i32(i32, i32) #4
|
||||
@@ -171,9 +172,9 @@ declare i32 @llvm.smax.i32(i32, i32) #4
|
||||
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
|
||||
declare i32 @llvm.umax.i32(i32, i32) #4
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
||||
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
+7
-5
@@ -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 triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
@@ -148,12 +150,12 @@ define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value,
|
||||
entry:
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
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
|
||||
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
|
||||
store i32 4, ptr %2, align 4
|
||||
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
|
||||
store ptr %itf.typecode, ptr %3, align 4
|
||||
%.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
|
||||
store i32 4, ptr %.repack1, align 4
|
||||
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
||||
store ptr %itf.typecode, ptr %2, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #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
|
||||
|
||||
+40
-37
@@ -3,29 +3,32 @@ 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 triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, ptr) #1
|
||||
declare void @main.regularFunction(i32, ptr) #2
|
||||
|
||||
declare void @runtime.deadlock(ptr) #1
|
||||
declare void @runtime.deadlock(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
|
||||
@@ -36,17 +39,17 @@ entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
|
||||
declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -61,16 +64,16 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 3, ptr %n, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef)
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %n, ptr %1, align 4
|
||||
@@ -81,7 +84,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
store i32 7, ptr %context, align 4
|
||||
ret void
|
||||
@@ -98,14 +101,14 @@ entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #1
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
@@ -129,42 +132,42 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.chanClose(ptr %ch, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1
|
||||
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef)
|
||||
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
|
||||
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
|
||||
store i32 4, ptr %2, align 4
|
||||
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
|
||||
store ptr %itf.typecode, ptr %3, align 4
|
||||
%.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
|
||||
store i32 4, ptr %.repack1, align 4
|
||||
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
|
||||
store ptr %itf.typecode, ptr %2, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
|
||||
ret void
|
||||
}
|
||||
@@ -186,13 +189,13 @@ entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
|
||||
attributes #4 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
|
||||
attributes #6 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
attributes #8 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
|
||||
attributes #9 = { nounwind }
|
||||
|
||||
Vendored
+28
-27
@@ -20,52 +20,53 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef)
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
|
||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||
@@ -77,10 +78,10 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
|
||||
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
@@ -95,7 +96,7 @@ typeassert.ok: ; preds = %entry
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
@@ -110,7 +111,7 @@ typeassert.ok: ; preds = %entry
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
|
||||
ret i8 %0
|
||||
@@ -119,22 +120,22 @@ entry:
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
|
||||
%1 = extractvalue %runtime._string %0, 0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef)
|
||||
ret %runtime._string %0
|
||||
}
|
||||
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #7 = { nounwind }
|
||||
|
||||
Vendored
+11
-12
@@ -6,45 +6,44 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret [0 x i32] zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %x
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
|
||||
Vendored
-16
@@ -48,22 +48,6 @@ func inlineFunc() {
|
||||
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.
|
||||
//
|
||||
//go:section .special_function_section
|
||||
|
||||
Vendored
+16
-28
@@ -14,27 +14,28 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @extern_func() #3 {
|
||||
define void @extern_func() #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @somepkg.someFunction2(ptr) #1
|
||||
declare void @somepkg.someFunction2(ptr) #3
|
||||
|
||||
; Function Attrs: inlinehint nounwind
|
||||
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
|
||||
@@ -48,19 +49,6 @@ entry:
|
||||
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
|
||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
|
||||
entry:
|
||||
@@ -83,15 +71,15 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #3
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
|
||||
|
||||
Vendored
+43
-42
@@ -6,28 +6,29 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %ints.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %ints.cap
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %ints.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -42,14 +43,14 @@ lookup.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
declare void @runtime.lookupPanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef)
|
||||
store i32 1, ptr %varargs, align 4
|
||||
%0 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 1
|
||||
store i32 2, ptr %0, align 4
|
||||
@@ -62,14 +63,14 @@ entry:
|
||||
%2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
|
||||
%3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1
|
||||
%4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %4
|
||||
}
|
||||
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
|
||||
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
|
||||
@@ -79,21 +80,21 @@ entry:
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
|
||||
ret i32 %copy.n
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1
|
||||
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
@@ -104,7 +105,7 @@ slice.next: ; preds = %entry
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
@@ -112,10 +113,10 @@ slice.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.slicePanic(ptr) #1
|
||||
declare void @runtime.slicePanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
@@ -127,7 +128,7 @@ slice.next: ; preds = %entry
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
@@ -136,7 +137,7 @@ slice.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
||||
@@ -148,7 +149,7 @@ slice.next: ; preds = %entry
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
@@ -157,7 +158,7 @@ slice.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
||||
@@ -169,7 +170,7 @@ slice.next: ; preds = %entry
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %2
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
@@ -178,26 +179,26 @@ slice.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = getelementptr i8, ptr %p, i32 %len
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = trunc i64 %len to i32
|
||||
%1 = getelementptr i8, ptr %p, i32 %0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef)
|
||||
ret ptr %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = icmp ult i32 %s.len, 4
|
||||
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
||||
@@ -210,14 +211,14 @@ slicetoarray.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #1
|
||||
declare void @runtime.sliceToArrayPointerPanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef)
|
||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
slicetoarray.next: ; preds = %entry
|
||||
@@ -228,7 +229,7 @@ slicetoarray.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i32 %len, 1073741823
|
||||
@@ -242,7 +243,7 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %7
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
@@ -250,10 +251,10 @@ unsafe.Slice.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #1
|
||||
declare void @runtime.unsafeSlicePanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp eq ptr %ptr, null
|
||||
@@ -266,7 +267,7 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1
|
||||
%6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %6
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
@@ -275,7 +276,7 @@ unsafe.Slice.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -290,7 +291,7 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
@@ -299,7 +300,7 @@ unsafe.Slice.throw: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
|
||||
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
@@ -314,7 +315,7 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
|
||||
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef)
|
||||
ret { ptr, i32, i32 } %8
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
@@ -322,7 +323,7 @@ unsafe.Slice.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+16
-15
@@ -10,34 +10,35 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret %runtime._string { ptr @"main$string", i32 3 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
|
||||
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret %runtime._string zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret i32 %s.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
@@ -52,19 +53,19 @@ lookup.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(ptr) #1
|
||||
declare void @runtime.lookupPanic(ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
|
||||
%1 = xor i1 %0, true
|
||||
@@ -72,16 +73,16 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
|
||||
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
|
||||
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = zext i8 %x to i32
|
||||
%.not = icmp ult i32 %0, %s.len
|
||||
@@ -97,7 +98,7 @@ lookup.throw: ; preds = %entry
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
Vendored
+17
-16
@@ -8,16 +8,17 @@ target triple = "wasm32-unknown-wasi"
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
|
||||
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -39,17 +40,17 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4
|
||||
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
declare void @runtime.memzero(ptr, i32, ptr) #1
|
||||
declare void @runtime.memzero(ptr, i32, ptr) #4
|
||||
|
||||
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1
|
||||
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4
|
||||
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 {
|
||||
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca %main.hasPadding, align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -70,10 +71,10 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1
|
||||
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #4
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -100,7 +101,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
|
||||
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%hashmap.key = alloca [2 x %main.hasPadding], align 8
|
||||
%hashmap.value = alloca i32, align 4
|
||||
@@ -127,14 +128,14 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #2 {
|
||||
define hidden void @main.main(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
@@ -24,8 +24,6 @@ func TestErrors(t *testing.T) {
|
||||
{name: "cgo"},
|
||||
{name: "compiler"},
|
||||
{name: "interp"},
|
||||
{name: "invalidmain"},
|
||||
{name: "invalidname"},
|
||||
{name: "linker-flashoverflow", target: "cortex-m-qemu"},
|
||||
{name: "linker-ramoverflow", target: "cortex-m-qemu"},
|
||||
{name: "linker-undefined", target: "darwin/arm64"},
|
||||
|
||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1728500571,
|
||||
"narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=",
|
||||
"lastModified": 1703068421,
|
||||
"narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0",
|
||||
"rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-24.05",
|
||||
"ref": "nixos-23.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
inputs = {
|
||||
# Use a recent stable release, but fix the version to make it reproducible.
|
||||
# This version should be updated from time to time.
|
||||
nixpkgs.url = "nixpkgs/nixos-24.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-23.11";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
@@ -49,11 +49,11 @@
|
||||
buildInputs = [
|
||||
# These dependencies are required for building tinygo (go install).
|
||||
go
|
||||
llvmPackages_18.llvm
|
||||
llvmPackages_18.libclang
|
||||
llvmPackages_17.llvm
|
||||
llvmPackages_17.libclang
|
||||
# Additional dependencies needed at runtime, for building and/or
|
||||
# flashing.
|
||||
llvmPackages_18.lld
|
||||
llvmPackages_17.lld
|
||||
avrdude
|
||||
binaryen
|
||||
# Additional dependencies needed for on-chip debugging.
|
||||
@@ -68,7 +68,7 @@
|
||||
# Without setting these explicitly, Homebrew versions might be used
|
||||
# or the default `ar` and `nm` tools might be used (which don't
|
||||
# support wasi).
|
||||
export CLANG="clang-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_NM=llvm-nm
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
export MD5SUM=md5sum
|
||||
|
||||
# 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"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
github.com/tetratelabs/wazero v1.6.0
|
||||
go.bug.st/serial v1.6.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8
|
||||
tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -12,6 +12,7 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
@@ -44,18 +45,19 @@ github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3px
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/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/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
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/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -74,5 +76,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0 h1:aN9rSxvVWmipB13yVAFOmRj3LX4Kkfiq/fSl5EAilDA=
|
||||
tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
+9
-46
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.34.0"
|
||||
const version = "0.33.0-dev"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
@@ -34,64 +34,27 @@ func GetGorootVersion() (major, minor int, err error) {
|
||||
if err != nil {
|
||||
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
|
||||
// major, minor, and patch version: 1, 3, and 2 in this example.
|
||||
// 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 version == "" || version[:2] != "go" {
|
||||
return 0, 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
|
||||
if s == "" || s[:2] != "go" {
|
||||
return 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 {
|
||||
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.
|
||||
var trailing string
|
||||
n, err := fmt.Sscanf(version, "go%d.%d.%d%s", &major, &minor, &patch, &trailing)
|
||||
if n == 2 {
|
||||
n, err = fmt.Sscanf(version, "go%d.%d%s", &major, &minor, &trailing)
|
||||
}
|
||||
if n >= 2 && err == io.EOF {
|
||||
n, err := fmt.Sscanf(s, "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)
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 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 0, 0, fmt.Errorf("failed to parse version: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GorootVersionString returns the version string as reported by the Go
|
||||
|
||||
@@ -1,71 +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},
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,11 @@ module github.com/tinygo-org/tinygo/internal/tools
|
||||
|
||||
go 1.22.4
|
||||
|
||||
require github.com/bytecodealliance/wasm-tools-go v0.3.0
|
||||
require github.com/ydnar/wasm-tools-go v0.1.4
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.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 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,46 +1,25 @@
|
||||
github.com/bytecodealliance/wasm-tools-go v0.3.0 h1:9aeDFYpbi3gtIW/nJCH+P+LhFMqezGoOfzqbUZLadho=
|
||||
github.com/bytecodealliance/wasm-tools-go v0.3.0/go.mod h1:VY+9FlpLi6jnhCrZLkyJjF9rjU4aEekgaRTk28MS2JE=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/klauspost/compress v1.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/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/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.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=
|
||||
github.com/ydnar/wasm-tools-go v0.1.4 h1:+25WqBj0AhLx8OFvZvrs7bQO6L3WtQ7t6JzQEYsXQb8=
|
||||
github.com/ydnar/wasm-tools-go v0.1.4/go.mod h1:lQfv2Tde3tRgZDSYriro0EmdSHzP1mrHPMmYNahSS/g=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
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=
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package tools
|
||||
|
||||
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
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -26,7 +24,6 @@ type runner struct {
|
||||
dataPtrType llvm.Type // often used type so created in advance
|
||||
uintptrType llvm.Type // equivalent to uintptr in Go
|
||||
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
|
||||
pkgName string // package name of the currently executing package
|
||||
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{
|
||||
mod: mod,
|
||||
targetData: llvm.NewTargetData(mod.DataLayout()),
|
||||
byteOrder: llvmutil.ByteOrder(mod.Target()),
|
||||
debug: debug,
|
||||
functionCache: make(map[llvm.Value]*function),
|
||||
objects: []object{{}},
|
||||
|
||||
+49
-49
@@ -173,7 +173,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
case 3:
|
||||
// Conditional branch: [cond, thenBB, elseBB]
|
||||
lastBB = currentBB
|
||||
switch operands[0].Uint(r) {
|
||||
switch operands[0].Uint() {
|
||||
case 1: // true -> thenBB
|
||||
currentBB = int(operands[1].(literalValue).value.(uint32))
|
||||
case 0: // false -> elseBB
|
||||
@@ -191,12 +191,12 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
case llvm.Switch:
|
||||
// Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...]
|
||||
value := operands[0].Uint(r)
|
||||
targetLabel := operands[1].Uint(r) // default label
|
||||
value := operands[0].Uint()
|
||||
targetLabel := operands[1].Uint() // default label
|
||||
// Do a lazy switch by iterating over all cases.
|
||||
for i := 2; i < len(operands); i += 2 {
|
||||
if value == operands[i].Uint(r) {
|
||||
targetLabel = operands[i+1].Uint(r)
|
||||
if value == operands[i].Uint() {
|
||||
targetLabel = operands[i+1].Uint()
|
||||
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
|
||||
// the second and third operand based on the boolean first operand.
|
||||
var result value
|
||||
switch operands[0].Uint(r) {
|
||||
switch operands[0].Uint() {
|
||||
case 1:
|
||||
result = operands[1]
|
||||
case 0:
|
||||
@@ -282,7 +282,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// by creating a global variable.
|
||||
|
||||
// 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.
|
||||
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)
|
||||
// return int(n)
|
||||
// }
|
||||
dstLen := operands[3].Uint(r)
|
||||
srcLen := operands[4].Uint(r)
|
||||
elemSize := operands[5].Uint(r)
|
||||
dstLen := operands[3].Uint()
|
||||
srcLen := operands[4].Uint()
|
||||
elemSize := operands[5].Uint()
|
||||
n := srcLen
|
||||
if n > dstLen {
|
||||
n = dstLen
|
||||
@@ -374,7 +374,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
nBytes := uint32(operands[3].Uint(r))
|
||||
nBytes := uint32(operands[3].Uint())
|
||||
dstObj := mem.getWritable(dst.index())
|
||||
dstBuf := dstObj.buffer.asRawValue(r)
|
||||
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.
|
||||
var offset int64
|
||||
for i := 1; i < len(operands); i += 2 {
|
||||
index := operands[i].Int(r)
|
||||
elementSize := operands[i+1].Int(r)
|
||||
index := operands[i].Int()
|
||||
elementSize := operands[i+1].Int()
|
||||
if elementSize < 0 {
|
||||
// This is a struct field.
|
||||
offset += index
|
||||
@@ -677,7 +677,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
// 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))
|
||||
continue
|
||||
}
|
||||
@@ -739,11 +739,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
var lhs, rhs float64
|
||||
switch operands[0].len(r) {
|
||||
case 8:
|
||||
lhs = math.Float64frombits(operands[0].Uint(r))
|
||||
rhs = math.Float64frombits(operands[1].Uint(r))
|
||||
lhs = math.Float64frombits(operands[0].Uint())
|
||||
rhs = math.Float64frombits(operands[1].Uint())
|
||||
case 4:
|
||||
lhs = float64(math.Float32frombits(uint32(operands[0].Uint(r))))
|
||||
rhs = float64(math.Float32frombits(uint32(operands[1].Uint(r))))
|
||||
lhs = float64(math.Float32frombits(uint32(operands[0].Uint())))
|
||||
rhs = float64(math.Float32frombits(uint32(operands[1].Uint())))
|
||||
default:
|
||||
panic("unknown float type")
|
||||
}
|
||||
@@ -782,23 +782,23 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if inst.opcode == llvm.Add {
|
||||
// This likely means this is part of a
|
||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint(r)))
|
||||
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
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
|
||||
// src/strings/builder.go in the Go source tree. This is
|
||||
// the identity operator, so we can return the input.
|
||||
locals[inst.localIndex] = lhs
|
||||
} else if inst.opcode == llvm.And && rhs.Uint(r) < 8 {
|
||||
} else if inst.opcode == llvm.And && rhs.Uint() < 8 {
|
||||
// This is probably part of a pattern to get the lower bits
|
||||
// of a pointer for pointer tagging, like this:
|
||||
// uintptr(unsafe.Pointer(t)) & 0b11
|
||||
// We can actually support this easily by ANDing with the
|
||||
// pointer offset.
|
||||
result := uint64(lhsPtr.offset()) & rhs.Uint(r)
|
||||
result := uint64(lhsPtr.offset()) & rhs.Uint()
|
||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||
} else {
|
||||
// Catch-all for weird operations that should just be done
|
||||
@@ -813,31 +813,31 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
var result uint64
|
||||
switch inst.opcode {
|
||||
case llvm.Add:
|
||||
result = lhs.Uint(r) + rhs.Uint(r)
|
||||
result = lhs.Uint() + rhs.Uint()
|
||||
case llvm.Sub:
|
||||
result = lhs.Uint(r) - rhs.Uint(r)
|
||||
result = lhs.Uint() - rhs.Uint()
|
||||
case llvm.Mul:
|
||||
result = lhs.Uint(r) * rhs.Uint(r)
|
||||
result = lhs.Uint() * rhs.Uint()
|
||||
case llvm.UDiv:
|
||||
result = lhs.Uint(r) / rhs.Uint(r)
|
||||
result = lhs.Uint() / rhs.Uint()
|
||||
case llvm.SDiv:
|
||||
result = uint64(lhs.Int(r) / rhs.Int(r))
|
||||
result = uint64(lhs.Int() / rhs.Int())
|
||||
case llvm.URem:
|
||||
result = lhs.Uint(r) % rhs.Uint(r)
|
||||
result = lhs.Uint() % rhs.Uint()
|
||||
case llvm.SRem:
|
||||
result = uint64(lhs.Int(r) % rhs.Int(r))
|
||||
result = uint64(lhs.Int() % rhs.Int())
|
||||
case llvm.Shl:
|
||||
result = lhs.Uint(r) << rhs.Uint(r)
|
||||
result = lhs.Uint() << rhs.Uint()
|
||||
case llvm.LShr:
|
||||
result = lhs.Uint(r) >> rhs.Uint(r)
|
||||
result = lhs.Uint() >> rhs.Uint()
|
||||
case llvm.AShr:
|
||||
result = uint64(lhs.Int(r) >> rhs.Uint(r))
|
||||
result = uint64(lhs.Int() >> rhs.Uint())
|
||||
case llvm.And:
|
||||
result = lhs.Uint(r) & rhs.Uint(r)
|
||||
result = lhs.Uint() & rhs.Uint()
|
||||
case llvm.Or:
|
||||
result = lhs.Uint(r) | rhs.Uint(r)
|
||||
result = lhs.Uint() | rhs.Uint()
|
||||
case llvm.Xor:
|
||||
result = lhs.Uint(r) ^ rhs.Uint(r)
|
||||
result = lhs.Uint() ^ rhs.Uint()
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
@@ -855,11 +855,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// and then truncating it as necessary.
|
||||
var value uint64
|
||||
if inst.opcode == llvm.SExt {
|
||||
value = uint64(operands[0].Int(r))
|
||||
value = uint64(operands[0].Int())
|
||||
} else {
|
||||
value = operands[0].Uint(r)
|
||||
value = operands[0].Uint()
|
||||
}
|
||||
bitwidth := operands[1].Uint(r)
|
||||
bitwidth := operands[1].Uint()
|
||||
if r.debug {
|
||||
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
|
||||
switch inst.opcode {
|
||||
case llvm.SIToFP:
|
||||
value = float64(operands[0].Int(r))
|
||||
value = float64(operands[0].Int())
|
||||
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 {
|
||||
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
|
||||
case llvm.IntUGT:
|
||||
return lhs.Uint(r) > rhs.Uint(r)
|
||||
return lhs.Uint() > rhs.Uint()
|
||||
case llvm.IntUGE:
|
||||
return lhs.Uint(r) >= rhs.Uint(r)
|
||||
return lhs.Uint() >= rhs.Uint()
|
||||
case llvm.IntULT:
|
||||
return lhs.Uint(r) < rhs.Uint(r)
|
||||
return lhs.Uint() < rhs.Uint()
|
||||
case llvm.IntULE:
|
||||
return lhs.Uint(r) <= rhs.Uint(r)
|
||||
return lhs.Uint() <= rhs.Uint()
|
||||
case llvm.IntSGT:
|
||||
return lhs.Int(r) > rhs.Int(r)
|
||||
return lhs.Int() > rhs.Int()
|
||||
case llvm.IntSGE:
|
||||
return lhs.Int(r) >= rhs.Int(r)
|
||||
return lhs.Int() >= rhs.Int()
|
||||
case llvm.IntSLT:
|
||||
return lhs.Int(r) < rhs.Int(r)
|
||||
return lhs.Int() < rhs.Int()
|
||||
case llvm.IntSLE:
|
||||
return lhs.Int(r) <= rhs.Int(r)
|
||||
return lhs.Int() <= rhs.Int()
|
||||
default:
|
||||
// _should_ be unreachable, until LLVM adds new icmp operands (unlikely)
|
||||
panic("interp: unsupported icmp")
|
||||
|
||||
+35
-41
@@ -361,8 +361,8 @@ type value interface {
|
||||
clone() value
|
||||
asPointer(*runner) (pointerValue, error)
|
||||
asRawValue(*runner) rawValue
|
||||
Uint(*runner) uint64
|
||||
Int(*runner) int64
|
||||
Uint() uint64
|
||||
Int() int64
|
||||
toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
|
||||
String() string
|
||||
}
|
||||
@@ -405,8 +405,7 @@ func (v literalValue) len(r *runner) uint32 {
|
||||
}
|
||||
|
||||
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(nil), 10)
|
||||
return strconv.FormatInt(v.Int(), 10)
|
||||
}
|
||||
|
||||
func (v literalValue) clone() value {
|
||||
@@ -422,13 +421,13 @@ func (v literalValue) asRawValue(r *runner) rawValue {
|
||||
switch value := v.value.(type) {
|
||||
case uint64:
|
||||
buf = make([]byte, 8)
|
||||
r.byteOrder.PutUint64(buf, value)
|
||||
binary.LittleEndian.PutUint64(buf, value)
|
||||
case uint32:
|
||||
buf = make([]byte, 4)
|
||||
r.byteOrder.PutUint32(buf, uint32(value))
|
||||
binary.LittleEndian.PutUint32(buf, uint32(value))
|
||||
case uint16:
|
||||
buf = make([]byte, 2)
|
||||
r.byteOrder.PutUint16(buf, uint16(value))
|
||||
binary.LittleEndian.PutUint16(buf, uint16(value))
|
||||
case uint8:
|
||||
buf = []byte{uint8(value)}
|
||||
default:
|
||||
@@ -441,7 +440,7 @@ func (v literalValue) asRawValue(r *runner) rawValue {
|
||||
return raw
|
||||
}
|
||||
|
||||
func (v literalValue) Uint(r *runner) uint64 {
|
||||
func (v literalValue) Uint() uint64 {
|
||||
switch value := v.value.(type) {
|
||||
case uint64:
|
||||
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) {
|
||||
case uint64:
|
||||
return int64(value)
|
||||
@@ -554,11 +553,11 @@ func (v pointerValue) asRawValue(r *runner) rawValue {
|
||||
return rv
|
||||
}
|
||||
|
||||
func (v pointerValue) Uint(r *runner) uint64 {
|
||||
func (v pointerValue) Uint() uint64 {
|
||||
panic("cannot convert pointer to integer")
|
||||
}
|
||||
|
||||
func (v pointerValue) Int(r *runner) int64 {
|
||||
func (v pointerValue) Int() int64 {
|
||||
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.
|
||||
if !v.hasPointer() {
|
||||
// Construct a fake runner, which is little endian.
|
||||
// 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.FormatInt(v.Int(), 10)
|
||||
}
|
||||
}
|
||||
return "<[…" + strconv.Itoa(len(v.buf)) + "]>"
|
||||
@@ -744,33 +738,33 @@ func (v rawValue) bytes() []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
func (v rawValue) Uint(r *runner) uint64 {
|
||||
func (v rawValue) Uint() uint64 {
|
||||
buf := v.bytes()
|
||||
|
||||
switch len(v.buf) {
|
||||
case 1:
|
||||
return uint64(buf[0])
|
||||
case 2:
|
||||
return uint64(r.byteOrder.Uint16(buf))
|
||||
return uint64(binary.LittleEndian.Uint16(buf))
|
||||
case 4:
|
||||
return uint64(r.byteOrder.Uint32(buf))
|
||||
return uint64(binary.LittleEndian.Uint32(buf))
|
||||
case 8:
|
||||
return r.byteOrder.Uint64(buf)
|
||||
return binary.LittleEndian.Uint64(buf)
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
}
|
||||
|
||||
func (v rawValue) Int(r *runner) int64 {
|
||||
func (v rawValue) Int() int64 {
|
||||
switch len(v.buf) {
|
||||
case 1:
|
||||
return int64(int8(v.Uint(r)))
|
||||
return int64(int8(v.Uint()))
|
||||
case 2:
|
||||
return int64(int16(v.Uint(r)))
|
||||
return int64(int16(v.Uint()))
|
||||
case 4:
|
||||
return int64(int32(v.Uint(r)))
|
||||
return int64(int32(v.Uint()))
|
||||
case 8:
|
||||
return int64(int64(v.Uint(r)))
|
||||
return int64(int64(v.Uint()))
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
@@ -884,11 +878,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
||||
var n uint64
|
||||
switch llvmType.IntTypeWidth() {
|
||||
case 64:
|
||||
n = rawValue{v.buf[:8]}.Uint(mem.r)
|
||||
n = rawValue{v.buf[:8]}.Uint()
|
||||
case 32:
|
||||
n = rawValue{v.buf[:4]}.Uint(mem.r)
|
||||
n = rawValue{v.buf[:4]}.Uint()
|
||||
case 16:
|
||||
n = rawValue{v.buf[:2]}.Uint(mem.r)
|
||||
n = rawValue{v.buf[:2]}.Uint()
|
||||
case 8:
|
||||
n = uint64(v.buf[0])
|
||||
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
|
||||
// (such as 0xe000ed00).
|
||||
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint(mem.r)
|
||||
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint()
|
||||
if ptr == 0 {
|
||||
// Null pointer.
|
||||
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
|
||||
case llvm.DoubleTypeKind:
|
||||
b := rawValue{v.buf[:8]}.Uint(mem.r)
|
||||
b := rawValue{v.buf[:8]}.Uint()
|
||||
f := math.Float64frombits(b)
|
||||
return llvm.ConstFloat(llvmType, f), nil
|
||||
case llvm.FloatTypeKind:
|
||||
b := uint32(rawValue{v.buf[:4]}.Uint(mem.r))
|
||||
b := uint32(rawValue{v.buf[:4]}.Uint())
|
||||
f := math.Float32frombits(b)
|
||||
return llvm.ConstFloat(llvmType, float64(f)), nil
|
||||
default:
|
||||
@@ -1071,19 +1065,19 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
|
||||
switch llvmValue.Type().IntTypeWidth() {
|
||||
case 64:
|
||||
var buf [8]byte
|
||||
r.byteOrder.PutUint64(buf[:], n)
|
||||
binary.LittleEndian.PutUint64(buf[:], n)
|
||||
for i, b := range buf {
|
||||
v.buf[i] = uint64(b)
|
||||
}
|
||||
case 32:
|
||||
var buf [4]byte
|
||||
r.byteOrder.PutUint32(buf[:], uint32(n))
|
||||
binary.LittleEndian.PutUint32(buf[:], uint32(n))
|
||||
for i, b := range buf {
|
||||
v.buf[i] = uint64(b)
|
||||
}
|
||||
case 16:
|
||||
var buf [2]byte
|
||||
r.byteOrder.PutUint16(buf[:], uint16(n))
|
||||
binary.LittleEndian.PutUint16(buf[:], uint16(n))
|
||||
for i, b := range buf {
|
||||
v.buf[i] = uint64(b)
|
||||
}
|
||||
@@ -1115,14 +1109,14 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
|
||||
case llvm.DoubleTypeKind:
|
||||
f, _ := llvmValue.DoubleValue()
|
||||
var buf [8]byte
|
||||
r.byteOrder.PutUint64(buf[:], math.Float64bits(f))
|
||||
binary.LittleEndian.PutUint64(buf[:], math.Float64bits(f))
|
||||
for i, b := range buf {
|
||||
v.buf[i] = uint64(b)
|
||||
}
|
||||
case llvm.FloatTypeKind:
|
||||
f, _ := llvmValue.DoubleValue()
|
||||
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 {
|
||||
v.buf[i] = uint64(b)
|
||||
}
|
||||
@@ -1172,11 +1166,11 @@ func (v localValue) asRawValue(r *runner) rawValue {
|
||||
panic("interp: localValue.asRawValue")
|
||||
}
|
||||
|
||||
func (v localValue) Uint(r *runner) uint64 {
|
||||
func (v localValue) Uint() uint64 {
|
||||
panic("interp: localValue.Uint")
|
||||
}
|
||||
|
||||
func (v localValue) Int(r *runner) int64 {
|
||||
func (v localValue) Int() int64 {
|
||||
panic("interp: localValue.Int")
|
||||
}
|
||||
|
||||
@@ -1260,7 +1254,7 @@ func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
|
||||
ptr, err := layoutValue.asPointer(r)
|
||||
if err == errIntegerAsPointer {
|
||||
// It's an integer, which means it's a small object or unknown.
|
||||
layout := layoutValue.Uint(r)
|
||||
layout := layoutValue.Uint()
|
||||
if layout == 0 {
|
||||
// Nil pointer, which means the layout is unknown.
|
||||
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.
|
||||
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:]
|
||||
rawBytes := make([]byte, len(rawByteValues))
|
||||
for i, v := range rawByteValues {
|
||||
|
||||
+1
-1
Submodule lib/macos-minimal-sdk updated: 4e4113e3b1...ebb736fda2
Submodule
+1
Submodule lib/renesas-svd added at 03d7688085
+24
-29
@@ -218,7 +218,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
||||
// with the TinyGo version. This is the case on some targets.
|
||||
func needsSyscallPackage(buildTags []string) bool {
|
||||
for _, tag := range buildTags {
|
||||
if tag == "baremetal" || tag == "nintendoswitch" || tag == "tinygo.wasm" {
|
||||
if tag == "baremetal" || tag == "darwin" || tag == "nintendoswitch" || tag == "tinygo.wasm" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -229,34 +229,29 @@ func needsSyscallPackage(buildTags []string) bool {
|
||||
// means use the TinyGo version.
|
||||
func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
paths := map[string]bool{
|
||||
"": true,
|
||||
"crypto/": true,
|
||||
"crypto/rand/": false,
|
||||
"crypto/tls/": false,
|
||||
"crypto/x509/": true,
|
||||
"crypto/x509/internal/": true,
|
||||
"crypto/x509/internal/macos/": false,
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/abi/": false,
|
||||
"internal/binary/": false,
|
||||
"internal/bytealg/": false,
|
||||
"internal/cm/": false,
|
||||
"internal/fuzz/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/gclayout": false,
|
||||
"internal/task/": false,
|
||||
"internal/wasi/": false,
|
||||
"machine/": false,
|
||||
"net/": true,
|
||||
"net/http/": false,
|
||||
"os/": true,
|
||||
"reflect/": false,
|
||||
"runtime/": false,
|
||||
"sync/": true,
|
||||
"testing/": true,
|
||||
"unique/": false,
|
||||
"": true,
|
||||
"crypto/": true,
|
||||
"crypto/rand/": false,
|
||||
"crypto/tls/": false,
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/binary/": false,
|
||||
"internal/bytealg/": false,
|
||||
"internal/cm/": false,
|
||||
"internal/fuzz/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/task/": false,
|
||||
"internal/wasi/": false,
|
||||
"machine/": false,
|
||||
"net/": true,
|
||||
"net/http/": false,
|
||||
"os/": true,
|
||||
"os/user/": false,
|
||||
"reflect/": false,
|
||||
"runtime/": false,
|
||||
"sync/": true,
|
||||
"testing/": true,
|
||||
}
|
||||
|
||||
if goMinor >= 19 {
|
||||
|
||||
+4
-16
@@ -180,7 +180,7 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
if len(fields) >= 2 {
|
||||
// There is some file/line/column information.
|
||||
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.Line = n
|
||||
pos.Column, _ = strconv.Atoi(fields[len(fields)-1])
|
||||
@@ -418,12 +418,8 @@ func (p *Package) Check() error {
|
||||
packageName := p.ImportPath
|
||||
if p == p.program.MainPkg() {
|
||||
if p.Name != "main" {
|
||||
return Errors{p, []error{
|
||||
scanner.Error{
|
||||
Pos: p.program.fset.Position(p.Files[0].Name.Pos()),
|
||||
Msg: fmt.Sprintf("expected main package to have name \"main\", not %#v", p.Name),
|
||||
},
|
||||
}}
|
||||
// Sanity check. Should not ever trigger.
|
||||
panic("expected main package to have name 'main'")
|
||||
}
|
||||
packageName = "main"
|
||||
}
|
||||
@@ -432,15 +428,7 @@ func (p *Package) Check() error {
|
||||
if err, ok := err.(Errors); ok {
|
||||
return err
|
||||
}
|
||||
if len(typeErrors) != 0 {
|
||||
// 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}}
|
||||
return Errors{p, typeErrors}
|
||||
}
|
||||
p.Pkg = typesPkg
|
||||
|
||||
|
||||
@@ -283,6 +283,48 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
// Tests are always run in the package directory.
|
||||
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.
|
||||
start := time.Now()
|
||||
err = cmd.Run()
|
||||
@@ -766,21 +808,25 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
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
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal).
|
||||
// If we're on a system without an environment, we need to pass command line
|
||||
// arguments and environment variables through global variables (built into
|
||||
// the binary directly) instead of the conventional way.
|
||||
needsEnvInVars := false
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
// we need to pass command line arguments and environment variables through
|
||||
// global variables (built into the binary directly) instead of the
|
||||
// conventional way.
|
||||
needsEnvInVars := config.GOOS() == "js"
|
||||
for _, tag := range config.BuildTags() {
|
||||
if tag == "baremetal" {
|
||||
needsEnvInVars = true
|
||||
}
|
||||
}
|
||||
var args, env []string
|
||||
var args, emuArgs, env []string
|
||||
var extraCmdEnv []string
|
||||
if needsEnvInVars {
|
||||
runtimeGlobals := make(map[string]string)
|
||||
@@ -800,6 +846,21 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
"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 {
|
||||
// Pass environment variables and command line parameters as usual.
|
||||
// This also works on qemu-aarch64 etc.
|
||||
@@ -842,61 +903,27 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
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" {
|
||||
var emuArgs []string
|
||||
|
||||
// Extract the wasmtime subcommand (e.g. "run" or "serve")
|
||||
if len(emulator) > 1 {
|
||||
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 {
|
||||
// Wasmtime needs some special flags to pass environment variables
|
||||
// and allow reading from the current directory.
|
||||
switch config.Options.Target {
|
||||
case "wasip1":
|
||||
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
|
||||
if ctx != nil {
|
||||
@@ -926,12 +953,12 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
|
||||
// Run binary.
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(cmd.Path, cmd.Args[1:]...)
|
||||
config.Options.PrintCommands(cmd.Path, cmd.Args...)
|
||||
}
|
||||
err = run(cmd, result)
|
||||
if err != nil {
|
||||
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()
|
||||
}
|
||||
return result, &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
@@ -1231,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) {
|
||||
val, ok := commandHelp[command]
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, usageDefault, goenv.Version(), os.Args[0], goenv.Get("GOCACHE"))
|
||||
switch command {
|
||||
default:
|
||||
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() {
|
||||
fmt.Fprintln(os.Stderr, "\nflags:")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stderr, "\nfor more details, see https://tinygo.org/docs/reference/usage/")
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, val)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func handleCompilerError(err error) {
|
||||
@@ -1438,20 +1332,19 @@ func (m globalValuesFlag) Set(value string) error {
|
||||
|
||||
// parseGoLinkFlag parses the -ldflags parameter. Its primary purpose right now
|
||||
// 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)
|
||||
globalVarValues := make(globalValuesFlag)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
err = set.Parse(flags)
|
||||
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
|
||||
@@ -1501,7 +1394,6 @@ func main() {
|
||||
var tags buildutil.TagsFlag
|
||||
flag.Var(&tags, "tags", "a space-separated list of extra build tags")
|
||||
target := flag.String("target", "", "chip/board name or JSON target specification file")
|
||||
buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared)")
|
||||
var stackSize uint64
|
||||
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
|
||||
size, err := bytesize.Parse(s)
|
||||
@@ -1571,7 +1463,6 @@ func main() {
|
||||
|
||||
// Early command processing, before commands are interpreted by the Go flag
|
||||
// library.
|
||||
handleChdirFlag()
|
||||
switch command {
|
||||
case "clang", "ld.lld", "wasm-ld":
|
||||
err := builder.RunTool(command, os.Args[2:]...)
|
||||
@@ -1584,7 +1475,7 @@ func main() {
|
||||
}
|
||||
|
||||
flag.CommandLine.Parse(os.Args[2:])
|
||||
globalVarValues, extLDFlags, err := parseGoLinkFlag(*ldflags)
|
||||
globalVarValues, err := parseGoLinkFlag(*ldflags)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
@@ -1610,7 +1501,6 @@ func main() {
|
||||
GOARM: goenv.Get("GOARM"),
|
||||
GOMIPS: goenv.Get("GOMIPS"),
|
||||
Target: *target,
|
||||
BuildMode: *buildMode,
|
||||
StackSize: stackSize,
|
||||
Opt: *opt,
|
||||
GC: *gc,
|
||||
@@ -1640,7 +1530,6 @@ func main() {
|
||||
Timeout: *timeout,
|
||||
WITPackage: witPackage,
|
||||
WITWorld: witWorld,
|
||||
ExtLDFlags: extLDFlags,
|
||||
}
|
||||
if *printCommands {
|
||||
options.PrintCommands = printCommand
|
||||
@@ -1742,7 +1631,7 @@ func main() {
|
||||
for i := range bufs {
|
||||
err := bufs[i].flush(os.Stdout, os.Stderr)
|
||||
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 {
|
||||
case fail <- struct{}{}:
|
||||
default:
|
||||
@@ -2059,56 +1948,3 @@ type outputEntry struct {
|
||||
stderr bool
|
||||
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:]...)
|
||||
}
|
||||
|
||||
+33
-307
@@ -6,7 +6,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
@@ -22,9 +21,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aykevl/go-wasm"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/diagnostics"
|
||||
@@ -40,7 +36,7 @@ var supportedLinuxArches = map[string]string{
|
||||
"X86Linux": "linux/386",
|
||||
"ARMLinux": "linux/arm/6",
|
||||
"ARM64Linux": "linux/arm64",
|
||||
"MIPSLinux": "linux/mips/hardfloat",
|
||||
"MIPSLinux": "linux/mipsle/hardfloat",
|
||||
"WASIp1": "wasip1/wasm",
|
||||
}
|
||||
|
||||
@@ -79,7 +75,6 @@ func TestBuild(t *testing.T) {
|
||||
"oldgo/",
|
||||
"print.go",
|
||||
"reflect.go",
|
||||
"signal.go",
|
||||
"slice.go",
|
||||
"sort.go",
|
||||
"stdlib.go",
|
||||
@@ -102,9 +97,6 @@ func TestBuild(t *testing.T) {
|
||||
if minor >= 22 {
|
||||
tests = append(tests, "go1.22/")
|
||||
}
|
||||
if minor >= 23 {
|
||||
tests = append(tests, "go1.23/")
|
||||
}
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
@@ -182,15 +174,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.Parallel()
|
||||
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
|
||||
@@ -218,7 +201,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
// isWebAssembly := strings.HasPrefix(spec.Triple, "wasm")
|
||||
isWASI := strings.HasPrefix(options.Target, "wasi")
|
||||
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 {
|
||||
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
|
||||
@@ -230,18 +212,11 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
}
|
||||
}
|
||||
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.
|
||||
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" {
|
||||
// Not all tests are currently supported on AVR.
|
||||
// Skip the ones that aren't.
|
||||
@@ -268,11 +243,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
// some compiler changes).
|
||||
continue
|
||||
|
||||
case "timers.go":
|
||||
// Crashes starting with Go 1.23.
|
||||
// Bug: https://github.com/llvm/llvm-project/issues/104032
|
||||
continue
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -283,13 +253,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
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
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@@ -323,10 +286,18 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest("rand.go", options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
if !isWebAssembly {
|
||||
// The recover() builtin isn't supported yet on WebAssembly and Windows.
|
||||
if !isWASI {
|
||||
// On WebAssembly, recover() needs the exception handling proposal which
|
||||
// isn't (as of 2024) implemented in wasmtime so this test is skipped on
|
||||
// WASI.
|
||||
t.Run("recover.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
options := options
|
||||
if isWebAssembly {
|
||||
// Hack: Asyncify doesn't support exception handling
|
||||
// instructions.
|
||||
options.Scheduler = "none"
|
||||
}
|
||||
runTest("recover.go", options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
@@ -405,13 +376,17 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
// of the path.
|
||||
path := TESTDATA + "/" + name
|
||||
// Get the expected output for this test.
|
||||
expectedOutputPath := path[:len(path)-3] + ".txt"
|
||||
txtpath := path[:len(path)-3] + ".txt"
|
||||
pkgName := "./" + path
|
||||
if path[len(path)-1] == '/' {
|
||||
expectedOutputPath = path + "out.txt"
|
||||
txtpath = path + "out.txt"
|
||||
options.Directory = path
|
||||
pkgName = "."
|
||||
}
|
||||
expected, err := os.ReadFile(txtpath)
|
||||
if err != nil {
|
||||
t.Fatal("could not read expected output file:", err)
|
||||
}
|
||||
|
||||
config, err := builder.NewConfig(&options)
|
||||
if err != nil {
|
||||
@@ -433,7 +408,10 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
return
|
||||
}
|
||||
|
||||
actual := stdout.Bytes()
|
||||
// putchar() prints CRLF, convert it to LF.
|
||||
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
|
||||
expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
|
||||
|
||||
if config.EmulatorName() == "simavr" {
|
||||
// Strip simavr log formatting.
|
||||
actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1)
|
||||
@@ -448,12 +426,17 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
}
|
||||
|
||||
// Check whether the command ran successfully.
|
||||
fail := false
|
||||
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))
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
@@ -471,21 +454,20 @@ func TestWebAssembly(t *testing.T) {
|
||||
t.Parallel()
|
||||
type testCase struct {
|
||||
name string
|
||||
target string
|
||||
panicStrategy string
|
||||
imports []string
|
||||
}
|
||||
for _, tc := range []testCase{
|
||||
// Test whether there really are no imports when using -panic=trap. This
|
||||
// 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-trap", target: "wasm-unknown", panicStrategy: "trap", imports: []string{}},
|
||||
{name: "panic-default", imports: []string{"wasi_snapshot_preview1.fd_write"}},
|
||||
{name: "panic-trap", panicStrategy: "trap", imports: []string{}},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpdir := t.TempDir()
|
||||
options := optionsFromTarget(tc.target, sema)
|
||||
options := optionsFromTarget("wasi", sema)
|
||||
options.PanicStrategy = tc.panicStrategy
|
||||
config, err := builder.NewConfig(&options)
|
||||
if err != nil {
|
||||
@@ -525,262 +507,6 @@ func TestWebAssembly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
mustCall(mod.ExportedFunction("_start").Call(ctx))
|
||||
} 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) {
|
||||
type testCase struct {
|
||||
name string
|
||||
buildMode string
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{name: "default"},
|
||||
{name: "c-shared", buildMode: "c-shared"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// 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())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
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) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
acces,access
|
||||
acuire,acquire
|
||||
addess,address
|
||||
adust,adjust
|
||||
@@ -6,36 +5,22 @@ 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,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
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package abi exposes low-level details of the Go compiler/runtime
|
||||
package abi
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package abi
|
||||
|
||||
// These two signatures are present to satisfy the expectation of some programs
|
||||
// (in particular internal/syscall/unix on MacOS). They do not currently have an
|
||||
// implementation, in part because TinyGo doesn't use ABI0 or ABIInternal (it
|
||||
// uses a C-like calling convention).
|
||||
// Calls to FuncPCABI0 however are treated specially by the compiler when
|
||||
// compiling for MacOS.
|
||||
|
||||
func FuncPCABI0(f interface{}) uintptr
|
||||
|
||||
func FuncPCABIInternal(f interface{}) uintptr
|
||||
@@ -30,8 +30,3 @@ func (littleEndian) AppendUint16(b []byte, v uint16) []byte {
|
||||
func (littleEndian) Uint32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
func (littleEndian) Uint64(b []byte) uint64 {
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
}
|
||||
|
||||
@@ -42,31 +42,6 @@ func Compare(a, b []byte) int {
|
||||
}
|
||||
}
|
||||
|
||||
// This function was copied from the Go 1.23 source tree (with runtime_cmpstring
|
||||
// manually inlined).
|
||||
func CompareString(a, b string) int {
|
||||
l := len(a)
|
||||
if len(b) < l {
|
||||
l = len(b)
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
c1, c2 := a[i], b[i]
|
||||
if c1 < c2 {
|
||||
return -1
|
||||
}
|
||||
if c1 > c2 {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
if len(a) < len(b) {
|
||||
return -1
|
||||
}
|
||||
if len(a) > len(b) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Count the number of instances of a byte in a slice.
|
||||
func Count(b []byte, c byte) int {
|
||||
// Use a simple implementation, as there is no intrinsic that does this like we want.
|
||||
|
||||
+4
-28
@@ -2,11 +2,6 @@ package cm
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// AnyInteger is a type constraint for any integer type.
|
||||
type AnyInteger interface {
|
||||
~int | ~uint | ~uintptr | ~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64
|
||||
}
|
||||
|
||||
// Reinterpret reinterprets the bits of type From into type T.
|
||||
// Will panic if the size of From is smaller than the size of To.
|
||||
func Reinterpret[T, From any](from From) (to T) {
|
||||
@@ -24,19 +19,19 @@ func LowerString[S ~string](s S) (*byte, uint32) {
|
||||
}
|
||||
|
||||
// LiftString lifts Core WebAssembly types into a [string].
|
||||
func LiftString[T ~string, Data unsafe.Pointer | uintptr | *uint8, Len AnyInteger](data Data, len Len) T {
|
||||
func LiftString[T ~string, Data unsafe.Pointer | uintptr | *uint8, Len uint | uintptr | uint32 | uint64](data Data, len Len) T {
|
||||
return T(unsafe.String((*uint8)(unsafe.Pointer(data)), int(len)))
|
||||
}
|
||||
|
||||
// LowerList lowers a [List] into a pair of Core WebAssembly types.
|
||||
func LowerList[L AnyList[T], T any](list L) (*T, uint32) {
|
||||
func LowerList[L ~struct{ list[T] }, T any](list L) (*T, uint32) {
|
||||
l := (*List[T])(unsafe.Pointer(&list))
|
||||
return l.data, uint32(l.len)
|
||||
}
|
||||
|
||||
// LiftList lifts Core WebAssembly types into a [List].
|
||||
func LiftList[L AnyList[T], T any, Data unsafe.Pointer | uintptr | *T, Len AnyInteger](data Data, len Len) L {
|
||||
return L(NewList((*T)(unsafe.Pointer(data)), len))
|
||||
func LiftList[L List[T], T any, Data unsafe.Pointer | uintptr | *T, Len uint | uintptr | uint32 | uint64](data Data, len Len) L {
|
||||
return L(NewList((*T)(unsafe.Pointer(data)), uint(len)))
|
||||
}
|
||||
|
||||
// BoolToU32 converts a value whose underlying type is [bool] into a [uint32].
|
||||
@@ -89,25 +84,6 @@ func F64ToU64(v float64) uint64 { return *(*uint64)(unsafe.Pointer(&v)) }
|
||||
// [Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md
|
||||
func U64ToF64(v uint64) float64 { return *(*float64)(unsafe.Pointer(&v)) }
|
||||
|
||||
// F32ToU64 maps the bits of a [float32] into a [uint64].
|
||||
// Used to lower a [float32] into a Core WebAssembly i64 when required by the [Canonical ABI].
|
||||
//
|
||||
// [float32]: https://pkg.go.dev/builtin#float32
|
||||
// [uint64]: https://pkg.go.dev/builtin#uint64
|
||||
// [Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md
|
||||
func F32ToU64(v float32) uint64 { return uint64(*(*uint32)(unsafe.Pointer(&v))) }
|
||||
|
||||
// U64ToF32 maps the bits of a [uint64] into a [float32].
|
||||
// Used to lift a Core WebAssembly i64 into a [float32] when required by the [Canonical ABI].
|
||||
//
|
||||
// [uint64]: https://pkg.go.dev/builtin#uint64
|
||||
// [float32]: https://pkg.go.dev/builtin#float32
|
||||
// [Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md
|
||||
func U64ToF32(v uint64) float32 {
|
||||
truncated := uint32(v)
|
||||
return *(*float32)(unsafe.Pointer(&truncated))
|
||||
}
|
||||
|
||||
// PointerToU32 converts a pointer of type *T into a [uint32].
|
||||
// Used to lower a pointer into a Core WebAssembly i32 as specified in the [Canonical ABI].
|
||||
//
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
//go:build !go1.23
|
||||
|
||||
package cm
|
||||
|
||||
// HostLayout marks a struct as using host memory layout.
|
||||
// See [structs.HostLayout] in Go 1.23 or later.
|
||||
type HostLayout struct {
|
||||
_ hostLayout // prevent accidental conversion with plain struct{}
|
||||
}
|
||||
|
||||
type hostLayout struct{}
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build go1.23
|
||||
|
||||
package cm
|
||||
|
||||
import "structs"
|
||||
|
||||
// HostLayout marks a struct as using host memory layout.
|
||||
// See [structs.HostLayout] in Go 1.23 or later.
|
||||
type HostLayout = structs.HostLayout
|
||||
+8
-20
@@ -4,25 +4,14 @@ import "unsafe"
|
||||
|
||||
// List represents a Component Model list.
|
||||
// The binary representation of list<T> is similar to a Go slice minus the cap field.
|
||||
type List[T any] struct {
|
||||
_ HostLayout
|
||||
list[T]
|
||||
}
|
||||
|
||||
// AnyList is a type constraint for generic functions that accept any [List] type.
|
||||
type AnyList[T any] interface {
|
||||
~struct {
|
||||
_ HostLayout
|
||||
list[T]
|
||||
}
|
||||
}
|
||||
type List[T any] struct{ list[T] }
|
||||
|
||||
// NewList returns a List[T] from data and len.
|
||||
func NewList[T any, Len AnyInteger](data *T, len Len) List[T] {
|
||||
func NewList[T any](data *T, len uint) List[T] {
|
||||
return List[T]{
|
||||
list: list[T]{
|
||||
list[T]{
|
||||
data: data,
|
||||
len: uintptr(len),
|
||||
len: len,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -31,16 +20,15 @@ func NewList[T any, Len AnyInteger](data *T, len Len) List[T] {
|
||||
// The underlying slice data is not copied, and the resulting List points at the
|
||||
// same array storage as the slice.
|
||||
func ToList[S ~[]T, T any](s S) List[T] {
|
||||
return NewList[T](unsafe.SliceData([]T(s)), uintptr(len(s)))
|
||||
return NewList[T](unsafe.SliceData([]T(s)), uint(len(s)))
|
||||
}
|
||||
|
||||
// list represents the internal representation of a Component Model list.
|
||||
// It is intended to be embedded in a [List], so embedding types maintain
|
||||
// the methods defined on this type.
|
||||
type list[T any] struct {
|
||||
_ HostLayout
|
||||
data *T
|
||||
len uintptr
|
||||
len uint
|
||||
}
|
||||
|
||||
// Slice returns a Go slice representing the List.
|
||||
@@ -54,7 +42,7 @@ func (l list[T]) Data() *T {
|
||||
}
|
||||
|
||||
// Len returns the length of the list.
|
||||
// TODO: should this return an int instead of a uintptr?
|
||||
func (l list[T]) Len() uintptr {
|
||||
// TODO: should this return an int instead of a uint?
|
||||
func (l list[T]) Len() uint {
|
||||
return l.len
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@ package cm
|
||||
// Option represents a Component Model [option<T>] type.
|
||||
//
|
||||
// [option<T>]: https://component-model.bytecodealliance.org/design/wit.html#options
|
||||
type Option[T any] struct {
|
||||
_ HostLayout
|
||||
option[T]
|
||||
}
|
||||
type Option[T any] struct{ option[T] }
|
||||
|
||||
// None returns an [Option] representing the none case,
|
||||
// equivalent to the zero value.
|
||||
@@ -17,7 +14,7 @@ func None[T any]() Option[T] {
|
||||
// Some returns an [Option] representing the some case.
|
||||
func Some[T any](v T) Option[T] {
|
||||
return Option[T]{
|
||||
option: option[T]{
|
||||
option[T]{
|
||||
isSome: true,
|
||||
some: v,
|
||||
},
|
||||
@@ -28,7 +25,6 @@ func Some[T any](v T) Option[T] {
|
||||
// The first byte is a bool representing none or some,
|
||||
// followed by storage for the associated type T.
|
||||
type option[T any] struct {
|
||||
_ HostLayout
|
||||
isSome bool
|
||||
some T
|
||||
}
|
||||
@@ -46,14 +42,3 @@ func (o *option[T]) Some() *T {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns T if o represents the some case,
|
||||
// or the zero value of T if o represents the none case.
|
||||
// This does not have a pointer receiver, so it can be chained.
|
||||
func (o option[T]) Value() T {
|
||||
if !o.isSome {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
return o.some
|
||||
}
|
||||
|
||||
@@ -17,22 +17,10 @@ type BoolResult bool
|
||||
// Result represents a result sized to hold the Shape type.
|
||||
// The size of the Shape type must be greater than or equal to the size of OK and Err types.
|
||||
// For results with two zero-length types, use [BoolResult].
|
||||
type Result[Shape, OK, Err any] struct {
|
||||
_ HostLayout
|
||||
result[Shape, OK, Err]
|
||||
}
|
||||
|
||||
// AnyResult is a type constraint for generic functions that accept any [Result] type.
|
||||
type AnyResult[Shape, OK, Err any] interface {
|
||||
~struct {
|
||||
_ HostLayout
|
||||
result[Shape, OK, Err]
|
||||
}
|
||||
}
|
||||
type Result[Shape, OK, Err any] struct{ result[Shape, OK, Err] }
|
||||
|
||||
// result represents the internal representation of a Component Model result type.
|
||||
type result[Shape, OK, Err any] struct {
|
||||
_ HostLayout
|
||||
isErr bool
|
||||
_ [0]OK
|
||||
_ [0]Err
|
||||
@@ -100,8 +88,8 @@ func (r *result[Shape, OK, Err]) validate() {
|
||||
|
||||
// OK returns an OK result with shape Shape and type OK and Err.
|
||||
// Pass Result[OK, OK, Err] or Result[Err, OK, Err] as the first type argument.
|
||||
func OK[R AnyResult[Shape, OK, Err], Shape, OK, Err any](ok OK) R {
|
||||
var r Result[Shape, OK, Err]
|
||||
func OK[R ~struct{ result[Shape, OK, Err] }, Shape, OK, Err any](ok OK) R {
|
||||
var r struct{ result[Shape, OK, Err] }
|
||||
r.validate()
|
||||
r.isErr = ResultOK
|
||||
*((*OK)(unsafe.Pointer(&r.data))) = ok
|
||||
@@ -110,8 +98,8 @@ func OK[R AnyResult[Shape, OK, Err], Shape, OK, Err any](ok OK) R {
|
||||
|
||||
// Err returns an error result with shape Shape and type OK and Err.
|
||||
// Pass Result[OK, OK, Err] or Result[Err, OK, Err] as the first type argument.
|
||||
func Err[R AnyResult[Shape, OK, Err], Shape, OK, Err any](err Err) R {
|
||||
var r Result[Shape, OK, Err]
|
||||
func Err[R ~struct{ result[Shape, OK, Err] }, Shape, OK, Err any](err Err) R {
|
||||
var r struct{ result[Shape, OK, Err] }
|
||||
r.validate()
|
||||
r.isErr = ResultErr
|
||||
*((*Err)(unsafe.Pointer(&r.data))) = err
|
||||
|
||||
@@ -4,7 +4,6 @@ package cm
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple[T0, T1 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
}
|
||||
@@ -13,7 +12,6 @@ type Tuple[T0, T1 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple3[T0, T1, T2 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -23,7 +21,6 @@ type Tuple3[T0, T1, T2 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple4[T0, T1, T2, T3 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -34,7 +31,6 @@ type Tuple4[T0, T1, T2, T3 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple5[T0, T1, T2, T3, T4 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -46,7 +42,6 @@ type Tuple5[T0, T1, T2, T3, T4 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple6[T0, T1, T2, T3, T4, T5 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -59,7 +54,6 @@ type Tuple6[T0, T1, T2, T3, T4, T5 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple7[T0, T1, T2, T3, T4, T5, T6 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -73,7 +67,6 @@ type Tuple7[T0, T1, T2, T3, T4, T5, T6 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple8[T0, T1, T2, T3, T4, T5, T6, T7 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -88,7 +81,6 @@ type Tuple8[T0, T1, T2, T3, T4, T5, T6, T7 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -104,7 +96,6 @@ type Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -121,7 +112,6 @@ type Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -139,7 +129,6 @@ type Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -158,7 +147,6 @@ type Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -178,7 +166,6 @@ type Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any] struct {
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -199,7 +186,6 @@ type Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any] str
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
@@ -221,7 +207,6 @@ type Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any
|
||||
//
|
||||
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
|
||||
type Tuple16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any] struct {
|
||||
_ HostLayout
|
||||
F0 T0
|
||||
F1 T1
|
||||
F2 T2
|
||||
|
||||
@@ -12,18 +12,7 @@ type Discriminant interface {
|
||||
// Variant represents a loosely-typed Component Model variant.
|
||||
// Shape and Align must be non-zero sized types. To create a variant with no associated
|
||||
// types, use an enum.
|
||||
type Variant[Tag Discriminant, Shape, Align any] struct {
|
||||
_ HostLayout
|
||||
variant[Tag, Shape, Align]
|
||||
}
|
||||
|
||||
// AnyVariant is a type constraint for generic functions that accept any [Variant] type.
|
||||
type AnyVariant[Tag Discriminant, Shape, Align any] interface {
|
||||
~struct {
|
||||
_ HostLayout
|
||||
variant[Tag, Shape, Align]
|
||||
}
|
||||
}
|
||||
type Variant[Tag Discriminant, Shape, Align any] struct{ variant[Tag, Shape, Align] }
|
||||
|
||||
// NewVariant returns a [Variant] with tag of type Disc, storage and GC shape of type Shape,
|
||||
// aligned to type Align, with a value of type T.
|
||||
@@ -37,7 +26,7 @@ func NewVariant[Tag Discriminant, Shape, Align any, T any](tag Tag, data T) Vari
|
||||
|
||||
// New returns a [Variant] with tag of type Disc, storage and GC shape of type Shape,
|
||||
// aligned to type Align, with a value of type T.
|
||||
func New[V AnyVariant[Tag, Shape, Align], Tag Discriminant, Shape, Align any, T any](tag Tag, data T) V {
|
||||
func New[V ~struct{ variant[Tag, Shape, Align] }, Tag Discriminant, Shape, Align any, T any](tag Tag, data T) V {
|
||||
validateVariant[Tag, Shape, Align, T]()
|
||||
var v variant[Tag, Shape, Align]
|
||||
v.tag = tag
|
||||
@@ -46,7 +35,7 @@ func New[V AnyVariant[Tag, Shape, Align], Tag Discriminant, Shape, Align any, T
|
||||
}
|
||||
|
||||
// Case returns a non-nil *T if the [Variant] case is equal to tag, otherwise it returns nil.
|
||||
func Case[T any, V AnyVariant[Tag, Shape, Align], Tag Discriminant, Shape, Align any](v *V, tag Tag) *T {
|
||||
func Case[T any, V ~struct{ variant[Tag, Shape, Align] }, Tag Discriminant, Shape, Align any](v *V, tag Tag) *T {
|
||||
validateVariant[Tag, Shape, Align, T]()
|
||||
v2 := (*variant[Tag, Shape, Align])(unsafe.Pointer(v))
|
||||
if v2.tag == tag {
|
||||
@@ -58,7 +47,6 @@ func Case[T any, V AnyVariant[Tag, Shape, Align], Tag Discriminant, Shape, Align
|
||||
// variant is the internal representation of a Component Model variant.
|
||||
// Shape and Align must be non-zero sized types.
|
||||
type variant[Tag Discriminant, Shape, Align any] struct {
|
||||
_ HostLayout
|
||||
tag Tag
|
||||
_ [0]Align
|
||||
data Shape // [unsafe.Sizeof(*(*Shape)(unsafe.Pointer(nil)))]byte
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package gclayout
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Internal constants for gc layout
|
||||
// See runtime/gc_precise.go
|
||||
|
||||
var (
|
||||
NoPtrs unsafe.Pointer
|
||||
Pointer unsafe.Pointer
|
||||
String unsafe.Pointer
|
||||
Slice unsafe.Pointer
|
||||
)
|
||||
|
||||
func init() {
|
||||
var sizeBits uintptr
|
||||
|
||||
switch unsafe.Sizeof(uintptr(0)) {
|
||||
case 8:
|
||||
sizeBits = 6
|
||||
case 4:
|
||||
sizeBits = 5
|
||||
case 2:
|
||||
sizeBits = 4
|
||||
}
|
||||
|
||||
var sizeShift = sizeBits + 1
|
||||
|
||||
NoPtrs = unsafe.Pointer(uintptr(0b0<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
|
||||
Pointer = unsafe.Pointer(uintptr(0b1<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
|
||||
String = unsafe.Pointer(uintptr(0b01<<sizeShift) | uintptr(0b10<<1) | uintptr(1))
|
||||
Slice = unsafe.Pointer(uintptr(0b001<<sizeShift) | uintptr(0b11<<1) | uintptr(1))
|
||||
}
|
||||
@@ -30,6 +30,3 @@ type Task struct {
|
||||
// the given function and falls back to the default stack size. It is replaced
|
||||
// with a load from a special section just before codegen.
|
||||
func getGoroutineStackSize(fn uintptr) uintptr
|
||||
|
||||
//go:linkname runtime_alloc runtime.alloc
|
||||
func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
@@ -35,16 +35,11 @@ type state struct {
|
||||
type stackState struct {
|
||||
// asyncify is the stack pointer of the asyncify stack.
|
||||
// This starts from the bottom and grows upwards.
|
||||
asyncifysp unsafe.Pointer
|
||||
asyncifysp uintptr
|
||||
|
||||
// asyncify is stack pointer of the C stack.
|
||||
// This starts from the top and grows downwards.
|
||||
csp unsafe.Pointer
|
||||
|
||||
// Pointer to the first (lowest address) of the stack. It must never be
|
||||
// overwritten. It can be checked from time to time to see whether a stack
|
||||
// overflow happened in the past.
|
||||
canaryPtr *uintptr
|
||||
csp uintptr
|
||||
}
|
||||
|
||||
// start creates and starts a new goroutine with the given function and arguments.
|
||||
@@ -68,18 +63,12 @@ func (s *state) initialize(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||
s.args = args
|
||||
|
||||
// Create a stack.
|
||||
stack := runtime_alloc(stackSize, nil)
|
||||
|
||||
// Set up the stack canary, a random number that should be checked when
|
||||
// switching from the task back to the scheduler. The stack canary pointer
|
||||
// points to the first word of the stack. If it has changed between now and
|
||||
// the next stack switch, there was a stack overflow.
|
||||
s.canaryPtr = (*uintptr)(stack)
|
||||
*s.canaryPtr = stackCanary
|
||||
stack := make([]uintptr, stackSize/unsafe.Sizeof(uintptr(0)))
|
||||
|
||||
// Calculate stack base addresses.
|
||||
s.asyncifysp = unsafe.Add(stack, unsafe.Sizeof(uintptr(0)))
|
||||
s.csp = unsafe.Add(stack, stackSize)
|
||||
s.asyncifysp = uintptr(unsafe.Pointer(&stack[0]))
|
||||
s.csp = uintptr(unsafe.Pointer(&stack[0])) + uintptr(len(stack))*unsafe.Sizeof(uintptr(0))
|
||||
stack[0] = stackCanary
|
||||
}
|
||||
|
||||
//go:linkname runqueuePushBack runtime.runqueuePushBack
|
||||
@@ -96,11 +85,14 @@ func Current() *Task {
|
||||
// Pause suspends the current task and returns to the scheduler.
|
||||
// This function may only be called when running on a goroutine stack, not when running on the system stack.
|
||||
func Pause() {
|
||||
if *currentTask.state.canaryPtr != stackCanary {
|
||||
// This is mildly unsafe but this is also the only place we can do this.
|
||||
if *(*uintptr)(unsafe.Pointer(currentTask.state.asyncifysp)) != stackCanary {
|
||||
runtimePanic("stack overflow")
|
||||
}
|
||||
|
||||
currentTask.state.unwind()
|
||||
|
||||
*(*uintptr)(unsafe.Pointer(currentTask.state.asyncifysp)) = stackCanary
|
||||
}
|
||||
|
||||
//export tinygo_unwind
|
||||
@@ -121,7 +113,7 @@ func (t *Task) Resume() {
|
||||
}
|
||||
currentTask = prevTask
|
||||
t.gcData.swap()
|
||||
if uintptr(t.state.asyncifysp) > uintptr(t.state.csp) {
|
||||
if t.state.asyncifysp > t.state.csp {
|
||||
runtimePanic("stack overflow")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,9 @@ var startTask [0]uint8
|
||||
//go:linkname runqueuePushBack runtime.runqueuePushBack
|
||||
func runqueuePushBack(*Task)
|
||||
|
||||
//go:linkname runtime_alloc runtime.alloc
|
||||
func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
// start creates and starts a new goroutine with the given function and arguments.
|
||||
// The new goroutine is scheduled to run later.
|
||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user