Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem 96187990e3 WIP mips 2023-02-19 20:54:41 +00:00
493 changed files with 5477 additions and 26616 deletions
+2 -2
View File
@@ -10,12 +10,12 @@ commands:
steps:
- restore_cache:
keys:
- llvm-source-16-v3
- llvm-source-14-v3
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-16-v3
key: llvm-source-14-v3
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
+7 -9
View File
@@ -27,13 +27,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-macos-v1
key: llvm-source-15-macos-v3
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -58,7 +58,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-macos-v1
key: llvm-build-15-macos-v4
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -87,11 +87,9 @@ jobs:
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: make gen-device
run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
run: make test GOTESTFLAGS="-v -short"
- name: Build TinyGo release tarball
run: make release -j3
- name: Test stdlib packages
@@ -108,7 +106,7 @@ jobs:
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v2
with:
name: darwin-amd64-double-zipped
name: release-double-zipped
path: build/tinygo.darwin-amd64.tar.gz
- name: Smoke tests
shell: bash
@@ -120,13 +118,13 @@ jobs:
- name: Install LLVM
shell: bash
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@16
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@15
- name: Checkout
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Build TinyGo
run: go install
+2 -2
View File
@@ -31,7 +31,7 @@ jobs:
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository_owner }}/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
@@ -53,7 +53,7 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-contexts: tinygo-llvm-build=docker-image://tinygo/llvm-16
build-contexts: tinygo-llvm-build=docker-image://tinygo/llvm-15
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on Github Actions
+16 -17
View File
@@ -18,7 +18,7 @@ jobs:
# statically linked binary.
runs-on: ubuntu-latest
container:
image: golang:1.21-alpine
image: golang:1.20-alpine
steps:
- name: Install apk dependencies
# tar: needed for actions/cache@v3
@@ -43,7 +43,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-linux-alpine-v1
key: llvm-source-15-linux-alpine-v3
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -68,7 +68,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-linux-alpine-v1
key: llvm-build-15-linux-alpine-v4
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -135,7 +135,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Install wasmtime
run: |
@@ -153,7 +153,6 @@ jobs:
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- run: make tinygo-test-wasi-fast
- run: make tinygo-test-wasip1-fast
- run: make smoketest
assert-test-linux:
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
@@ -178,12 +177,12 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '14'
- name: Install wasmtime
run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
@@ -194,7 +193,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-linux-asserts-v1
key: llvm-source-15-linux-asserts-v3
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -219,7 +218,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-linux-asserts-v1
key: llvm-build-15-linux-asserts-v4
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -276,7 +275,7 @@ jobs:
# in that process to avoid doing lots of duplicate work and to avoid
# complications around precompiled libraries such as compiler-rt shipped as
# part of the release tarball.
runs-on: ubuntu-20.04
runs-on: ubuntu-18.04
needs: build-linux
steps:
- name: Checkout
@@ -291,13 +290,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-linux-v1
key: llvm-source-15-linux-v3
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -322,7 +321,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-linux-arm-v1
key: llvm-build-15-linux-arm-v4
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -392,7 +391,7 @@ jobs:
# in that process to avoid doing lots of duplicate work and to avoid
# complications around precompiled libraries such as compiler-rt shipped as
# part of the release tarball.
runs-on: ubuntu-20.04
runs-on: ubuntu-18.04
needs: build-linux
steps:
- name: Checkout
@@ -408,13 +407,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-linux-v1
key: llvm-source-15-linux-v3
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -439,7 +438,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-linux-arm64-v1
key: llvm-build-15-linux-arm64-v4
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
-63
View File
@@ -1,63 +0,0 @@
# This is the Github action to build and push the LLVM Docker image
# used by the tinygo/tinygo-dev Docker image.
#
# It only needs to be rebuilt when updating the LLVM version.
#
# To update, make any needed changes to this file,
# then push to the "build-llvm-image" branch.
#
# The needed image will be rebuilt, which will very likely take at least 1-2 hours.
name: LLVM
on:
push:
branches: [ build-llvm-image ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-push-llvm:
name: build-push-llvm
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
tinygo/llvm-16
ghcr.io/${{ github.repository_owner }}/llvm-16
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
target: tinygo-llvm-build
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
-96
View File
@@ -1,96 +0,0 @@
name: Binary size difference
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
sizediff:
runs-on: ubuntu-22.04
permissions:
pull-requests: write
steps:
# Prepare, install tools
- name: Add GOBIN to $PATH
run: |
echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # fetch all history (no sparse checkout)
submodules: true
- name: Install apt dependencies
run: |
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' | sudo tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install --no-install-recommends -y \
llvm-16-dev \
clang-16 \
libclang-16-dev \
lld-16
- name: Restore LLVM source cache
uses: actions/cache@v3
id: cache-llvm-source
with:
key: llvm-source-16-sizediff-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache Go
uses: actions/cache@v3
with:
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- run: make gen-device -j4
- name: Download drivers repo
run: git clone https://github.com/tinygo-org/drivers.git
- name: Save HEAD
run: git branch github-actions-saved-HEAD HEAD
# Compute sizes for the dev branch
- name: Checkout dev branch
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
- name: Build tinygo binary for the dev branch
run: go install
- name: Determine binary sizes on the dev branch
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
# Compute sizes for the PR branch
- name: Checkout PR branch
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
- name: Build tinygo binary for the PR branch
run: go install
- name: Determine binary sizes on the PR branch
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
# Create comment
# TODO: add a summary, something like:
# - overall size difference (percent)
# - number of binaries that grew / shrank / remained the same
# - don't show the full diff when no binaries changed
- name: Calculate size diff
run: ./tools/sizediff drivers/sizes-dev.txt drivers/sizes-pr.txt | tee sizediff.txt
- name: Create comment
run: |
echo "Size difference with the dev branch:" > comment.txt
echo "<details><summary>Binary size difference</summary>" >> comment.txt
echo "<pre>" >> comment.txt
cat sizediff.txt >> comment.txt
echo "</pre></details>" >> comment.txt
- name: Comment contents
run: cat comment.txt
- name: Add comment
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
uses: thollander/actions-comment-pull-request@v2.3.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
filePath: comment.txt
comment_tag: sizediff
+11 -13
View File
@@ -35,13 +35,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Restore cached LLVM source
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-windows-v1
key: llvm-source-15-windows-v4
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -66,7 +66,7 @@ jobs:
uses: actions/cache/restore@v3
id: cache-llvm-build
with:
key: llvm-build-16-windows-v2
key: llvm-build-15-windows-v5
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -97,11 +97,9 @@ jobs:
- name: Install wasmtime
run: |
scoop install wasmtime
- name: make gen-device
run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
run: make test GOTESTFLAGS="-v -short"
- name: Build TinyGo release tarball
shell: bash
run: make build/release -j4
@@ -118,7 +116,7 @@ jobs:
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v3
with:
name: windows-amd64-double-zipped
name: release-double-zipped
path: build/release/release.zip
smoke-test-windows:
@@ -143,12 +141,12 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
with:
name: windows-amd64-double-zipped
name: release-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
@@ -173,12 +171,12 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
with:
name: windows-amd64-double-zipped
name: release-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
@@ -209,12 +207,12 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.20'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
with:
name: windows-amd64-double-zipped
name: release-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
-3
View File
@@ -31,6 +31,3 @@
[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
+3 -233
View File
@@ -1,233 +1,3 @@
0.30.0
---
* **general**
- add LLVM 16 support, use it by default
* **compiler**
- `build`: work around a race condition by building Go SSA serially
- `compiler`: fix a crash by not using the LLVM global context types
- `interp`: don't copy unknown values in `runtime.sliceCopy` to fix miscompile
- `interp`: fix crash in error report by not returning raw LLVM values
* **standard library**
- `machine/usb/adc/midi`: various improvements and API changes
- `reflect`: add support for `[...]T``[]T` in reflect
* **targets**
- `atsamd21`, `atsamd51`: add support for USB INTERRUPT OUT
- `rp2040`: always use the USB device enumeration fix, even in chips that supposedly have the HW fix
- `wasm`: increase default stack size to 32k for wasi/wasm
* **boards**
- `gobadge`: add GoBadge target as alias for PyBadge :)
- `gemma-m0`: add support for the Adafruit Gemma M0
0.29.0
---
* **general**
- Go 1.21 support
- use https for renesas submodule #3856
- ci: rename release-double-zipped to something more useful
- ci: update Node.js from version 14 to version 16
- ci: switch GH actions builds to use Go 1.21 final release
- docker: update clang to version 15
- docker: use Go 1.21 for Docker dev container build
- `main`: add target JSON file in `tinygo info` output
- `main`: improve detection of filesystems
- `main`: use `go env` instead of doing all detection manually
- make: add make task to generate Renesas device wrappers
- make: add task to check NodeJS version before running tests
- add submodule for Renesas SVD file mirror repo
- update to go-serial package v1.6.0
- `testing`: add Testing function
- `tools/gen-device-svd`: small changes needed for Renesas MCUs
* **compiler**
- `builder`: update message for max supported Go version
- `compiler,reflect`: NumMethods reports exported methods only
- `compiler`: add compiler-rt and wasm symbols to table
- `compiler`: add compiler-rt to wasm.json
- `compiler`: add min and max builtin support
- `compiler`: implement clear builtin for maps
- `compiler`: implement clear builtin for slices
- `compiler`: improve panic message when a runtime call is unavailable
- `compiler`: update .ll test output
- `loader`: merge go.env file which is now required starting in Go 1.21 to correctly get required packages
* **standard library**
- `os`: define ErrNoDeadline
- `reflect`: Add FieldByNameFunc
- `reflect`: add SetZero
- `reflect`: fix iterating over maps with interface{} keys
- `reflect`: implement Value.Grow
- `reflect`: remove unecessary heap allocations
- `reflect`: use .key() instead of a type assert
- `sync`: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues
* **targets**
- `machine`: UART refactor (#3832)
- `machine/avr`: pin change interrupt
- `machine/macropad_rp2040`: add machine.BUTTON
- `machine/nrf`: add I2C timeout
- `machine/nrf`: wait for stop condition after reading from the I2C bus
- `machine/nRF52`: set SPI TX/RX lengths even data is empty. Fixes #3868 (#3877)
- `machine/rp2040`: add missing suffix to CMD_READ_STATUS
- `machine/rp2040`: add NoPin support
- `machine/rp2040`: move flash related functions into separate file from C imports for correct - LSP. Fixes #3852
- `machine/rp2040`: wait for 1000 us after flash reset to avoid issues with busy USB bus
- `machine/samd51,rp2040,nrf528xx,stm32`: implement watchdog
- `machine/samd51`: fix i2cTimeout was decreasing due to cache activation
- `machine/usb`: Add support for HID Keyboard LEDs
- `machine/usb`: allow USB Endpoint settings to be changed externally
- `machine/usb`: refactor endpoint configuration
- `machine/usb`: remove usbDescriptorConfig
- `machine/usb/hid,joystick`: fix hidreport (3) (#3802)
- `machine/usb/hid`: add RxHandler interface
- `machine/usb/hid`: rename Handler() to TxHandler()
- `wasi`: allow zero inodes when reading directories
- `wasm`: add support for GOOS=wasip1
- `wasm`: fix functions exported through //export
- `wasm`: remove i64 workaround, use BigInt instead
- `example`: adjust time offset
- `example`: simplify pininterrupt
* **boards**
- `targets`: add AKIZUKI DENSHI AE-RP2040
- `targets`: adding new uf2 target for PCA10056 (#3765)
0.28.0
---
* **general**
- fix parallelism in the compiler on Windows by building LLVM with thread support
- support qemu-user debugging
- make target JSON msd-volume-name an array
- print source location when a panic happens in -monitor
- `test`: don't print `ok` for a successful compile-only
* **compiler**
- `builder`: remove non-ThinLTO build mode
- `builder`: fail earlier if Go is not available
- `builder`: improve `-size=full` in a number of ways
- `builder`: implement Nordic DFU file writer in Go
- `cgo`: allow `LDFLAGS: --export=...`
- `compiler`: support recursive slice types
- `compiler`: zero struct padding during map operations
- `compiler`: add llvm.ident metadata
- `compiler`: remove `unsafe.Pointer(uintptr(v) + idx)` optimization (use `unsafe.Add` instead)
- `compiler`: add debug info to `//go:embed` data structures for better `-size` output
- `compiler`: add debug info to string constants
- `compiler`: fix a minor race condition
- `compiler`: emit correct alignment in debug info for global variables
- `compiler`: correctly generate reflect data for local named types
- `compiler`: add alloc attributes to `runtime.alloc`, reducing flash usage slightly
- `compiler`: for interface maps, use the original named type if available
- `compiler`: implement most math/bits functions as LLVM intrinsics
- `compiler`: ensure all defers have been seen before creating rundefers
* **standard library**
- `internal/task`: disallow blocking inside an interrupt
- `machine`: add `CPUReset`
- `machine/usb/hid`: add MediaKey support
- `machine/usb/hid/joystick`: move joystick under HID
- `machine/usb/hid/joystick`: allow joystick settings override
- `machine/usb/hid/joystick`: handle case where we cannot find the correct HID descriptor
- `machine/usb/hid/mouse`: add support for mouse back and forward
- `machine/usb`: add ability to override default VID, PID, manufacturer name, and product name
- `net`: added missing `TCPAddr` and `UDPAddr` implementations
- `os`: add IsTimeout function
- `os`: fix resource leak in `(*File).Close`
- `os`: add `(*File).Sync`
- `os`: implement `(*File).ReadDir` for wasi
- `os`: implement `(*File).WriteAt`
- `reflect`: make sure null bytes are supported in tags
- `reflect`: refactor this package to enable many new features
- `reflect`: add map type methods: `Elem` and `Key`
- `reflect`: add map methods: `MapIndex`, `MapRange`/`MapIter`, `SetMapIndex`, `MakeMap`, `MapKeys`
- `reflect`: add slice methods: `Append`, `MakeSlice`, `Slice`, `Slice3`, `Copy`, `Bytes`, `SetLen`
- `reflect`: add misc methods: `Zero`, `Addr`, `UnsafeAddr`, `OverflowFloat`, `OverflowInt`, `OverflowUint`, `SetBytes`, `Convert`, `CanInt`, `CanFloat`, `CanComplex`, `Comparable`
- `reflect`: add type methods: `String`, `PkgPath`, `FieldByName`, `FieldByIndex`, `NumMethod`
- `reflect`: add stubs for `Type.Method`, `CanConvert`, `ArrayOf`, `StructOf`, `MapOf`
- `reflect`: add stubs for channel select routines/types
- `reflect`: allow nil rawType to call Kind()
- `reflect`: ensure all ValueError panics have Kind fields
- `reflect`: add support for named types
- `reflect`: improve `Value.String()`
- `reflect`: set `Index` and `PkgPath` field in `Type.Field`
- `reflect`: `Type.AssignableTo`: you can assign anything to `interface{}`
- `reflect`: add type check to `Value.Field`
- `reflect`: let `TypeOf(nil)` return nil
- `reflect`: move `StructField.Anonymous` field to match upstream location
- `reflect`: add `UnsafePointer` for Func types
- `reflect`: `MapIter.Next` needs to allocate new keys/values every time
- `reflect`: fix `IsNil` for interfaces
- `reflect`: fix `Type.Name` to return an empty string for non-named types
- `reflect`: add `VisibleFields`
- `reflect`: properly handle embedded structs
- `reflect`: make sure `PointerTo` works for named types
- `reflect`: `Set`: convert non-interface to interface
- `reflect`: `Set`: fix direction of assignment check
- `reflect`: support channel directions
- `reflect`: print struct tags in Type.String()
- `reflect`: properly handle read-only values
- `runtime`: allow custom-gc SetFinalizer and clarify KeepAlive
- `runtime`: implement KeepAlive using inline assembly
- `runtime`: check for heap allocations inside interrupts
- `runtime`: properly turn pointer into empty interface when hashing
- `runtime`: improve map size hint usage
- `runtime`: zero map key/value on deletion to so GC doesn't see them
- `runtime`: print the address where a panic happened
- `runtime/debug`: stub `SetGCPercent`, `BuildInfo.Settings`
- `runtime/metrics`: add this package as a stub
- `syscall`: `Stat_t` timespec fields are Atimespec on darwin
- `syscall`: add `Timespec.Unix()` for wasi
- `syscall`: add fsync using libc
- `testing`: support -test.count
- `testing`: make test output unbuffered when verbose
- `testing`: add -test.skip
- `testing`: move runtime.GC() call to runN to match upstream
- `testing`: add -test.shuffle to order randomize test and benchmark order
* **targets**
- `arm64`: fix register save/restore to include vector registers
- `attiny1616`: add support for this chip
- `cortexm`: refactor EnableInterrupts and DisableInterrupts to avoid `arm.AsmFull`
- `cortexm`: enable functions in RAM for go & cgo
- `cortexm`: convert SystemStack from `AsmFull` to C inline assembly
- `cortexm`: fix crash due to wrong stack size offset
- `nrf`: samd21, stm32: add flash API
- `nrf`: fix memory issue in ADC read
- `nrf`: new peripheral type for nrf528xx chips
- `nrf`: implement target mode
- `nrf`: improve ADC and add oversampling, longer sample time, and reference voltage
- `rp2040`: change calling order for device enumeration fix to do first
- `rp2040`: rtc delayed interrupt
- `rp2040`: provide better errors for invalid pins on I2C and SPI
- `rp2040`: change uart to allow for a single pin
- `rp2040`: implement Flash interface
- `rp2040`: remove SPI `DataBits` property
- `rp2040`: unify all linker scripts using LDFLAGS
- `rp2040`: remove SPI deadline for improved performance
- `rp2040`: use 4MHz as default frequency for SPI
- `rp2040`: implement target mode
- `rp2040`: use DMA for send-only SPI transfers
- `samd21`: rearrange switch case for get pin cfg
- `samd21`: fix issue with WS2812 driver by making pin accesses faster
- `samd51`: enable CMCC cache for greatly improved performance
- `samd51`: remove extra BK0RDY clear
- `samd51`: implement Flash interface
- `samd51`: use correct SPI frequency
- `samd51`: remove extra BK0RDY clear
- `samd51`: fix ADC multisampling
- `wasi`: allow users to set the `runtime_memhash_tsip` or `runtime_memhash_fnv` build tags
- `wasi`: set `WASMTIME_BACKTRACE_DETAILS` when running in wasmtime.
- `wasm`: implement the `//go:wasmimport` directive
* **boards**
- `gameboy-advance`: switch to use register definitions in device/gba
- `gameboy-advance`: rename display and make pointer receivers
- `gopher-badge`: Added Gopher Badge support
- `lorae5`: add needed definition for UART2
- `lorae5`: correct mapping for I2C bus, add pin mapping to enable power
- `pinetime`: update the target file (rename from pinetime-devkit0)
- `qtpy`: fix bad pin assignment
- `wioterminal`: fix pin definition of BCM13
- `xiao`: Pins D4 & D5 are I2C1. Use pins D2 & D3 for I2C0.
- `xiao`: add DefaultUART
0.27.0
---
@@ -646,7 +416,7 @@
- `interp`: always run atomic and volatile loads/stores at runtime
- `interp`: bump timeout to 180 seconds
- `interp`: handle type assertions on nil interfaces
- `loader`: eliminate goroot cache inconsistency
- `loader`: elminate goroot cache inconsistency
- `loader`: respect $GOROOT when running `go list`
- `transform`: allocate the correct amount of bytes in an alloca
- `transform`: remove switched func lowering
@@ -1345,7 +1115,7 @@
- `sync`: add WaitGroup
* **targets**
- `arm`: allow nesting in DisableInterrupts and EnableInterrupts
- `arm`: make FPU configuration consistent
- `arm`: make FPU configuraton consistent
- `arm`: do not mask fault handlers in critical sections
- `atmega2560`: fix pin mapping for pins D2, D5 and the L port
- `atsamd`: return an error when an incorrect PWM pin is used
@@ -1374,7 +1144,7 @@
- `nrf`: add microbit-s110v8 target
- `nrf`: fix bug in SPI.Tx
- `nrf`: support debugging the PCA10056
- `pygamer`: add Adafruit PyGamer support
- `pygamer`: add Adafruit PyGamer suport
- `riscv`: fix interrupt configuration bug
- `riscv`: disable linker relaxations during gp init
- `stm32f4disco`: add new target with ST-Link v2.1 debugger
+2 -2
View File
@@ -1,8 +1,8 @@
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.21 AS tinygo-llvm
FROM golang:1.20 AS tinygo-llvm
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-15 ninja-build
apt-get install -y apt-utils make cmake clang-11 ninja-build
COPY ./Makefile /tinygo/Makefile
+2 -2
View File
@@ -1,7 +1,7 @@
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
TinyGo includes portions of the Go standard library.
Copyright (c) 2009-2023 The Go Authors. All rights reserved.
Copyright (c) 2009-2022 The Go Authors. All rights reserved.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
+16 -50
View File
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order.
LLVM_VERSIONS = 16 15 14 13 12 11
LLVM_VERSIONS = 15 14 13 12 11
errifempty = $(if $(1),$(1),$(error $(2)))
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
toolSearchPathsVersion = $(1)-$(2)
@@ -30,7 +30,7 @@ GO ?= go
export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test.
GOTESTFLAGS ?=
GOTESTFLAGS ?= -v
# md5sum binary
MD5SUM = md5sum
@@ -113,15 +113,17 @@ endif
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
ifeq ($(OS),Windows_NT)
EXE = .exe
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
# PIC needs to be disabled for libclang to work.
LLVM_OPTION += -DLLVM_ENABLE_PIC=OFF
# LLVM compiled using MinGW on Windows appears to have problems with threads.
# Without this flag, linking results in errors like these:
# libLLVMSupport.a(Threading.cpp.obj):Threading.cpp:(.text+0x55): undefined reference to `std::thread::hardware_concurrency()'
LLVM_OPTION += -DLLVM_ENABLE_THREADS=OFF -DLLVM_ENABLE_PIC=OFF
CGO_CPPFLAGS += -DCINDEX_NO_EXPORTS
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
@@ -154,7 +156,7 @@ LLD_LIB_NAMES = lldCOFF lldCommon lldELF lldMachO lldMinGW lldWasm
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
# Other libraries that are needed to link TinyGo.
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMRISCVTargetMCA LLVMX86TargetMCA
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMX86TargetMCA
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
@@ -170,7 +172,7 @@ NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(ad
# For static linking.
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++17
CGO_CXXFLAGS=-std=c++14
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
@@ -232,13 +234,9 @@ gen-device-rp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
GO111MODULE=off $(GO) fmt ./src/device/rp
gen-device-renesas: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
GO111MODULE=off $(GO) fmt ./src/device/renesas
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
git clone -b xtensa_release_16.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
git clone -b xtensa_release_15.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm
# Configure LLVM.
@@ -267,22 +265,12 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && make -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
# Check for Node.js used during WASM tests.
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
MIN_NODEJS_VERSION=16
.PHONY: check-nodejs-version
check-nodejs-version:
ifeq (, $(shell which node))
@echo "Install NodeJS version 16+ to run tests."; exit 1;
endif
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
# Build the Go compiler.
tinygo:
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc check-nodejs-version
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
@@ -293,7 +281,6 @@ TEST_PACKAGES_SLOW = \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \
compress/lzw \
compress/zlib \
container/heap \
container/list \
@@ -322,6 +309,7 @@ TEST_PACKAGES_FAST = \
internal/profile \
math \
math/cmplx \
net \
net/http/internal/ascii \
net/mail \
os \
@@ -346,6 +334,7 @@ endif
# archive/zip requires os.ReadAt, which is not yet supported on windows
# bytes requires mmap
# compress/flate appears to hang on wasi
# compress/lzw appears to hang on wasi
# 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
@@ -361,13 +350,13 @@ TEST_PACKAGES_LINUX := \
archive/zip \
bytes \
compress/flate \
compress/lzw \
crypto/hmac \
debug/dwarf \
debug/plan9obj \
image \
io/ioutil \
mime/quotedprintable \
net \
strconv \
testing/fstest \
text/tabwriter \
@@ -377,6 +366,7 @@ TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
TEST_PACKAGES_WINDOWS := \
compress/flate \
compress/lzw \
crypto/hmac \
strconv \
text/template/parse \
@@ -427,12 +417,8 @@ tinygo-bench-fast:
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasi:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasi-fast:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip1-fast:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-bench-wasi:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
@@ -488,24 +474,16 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/rtcinterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/time-offset
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@@ -550,16 +528,12 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=bluemicro840 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinket-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gemma-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
@@ -590,7 +564,7 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pinetime examples/blinky1
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
@$(MD5SUM) test.hex
@@ -664,10 +638,6 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
@@ -732,8 +702,6 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=attiny1616 examples/empty
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@@ -747,8 +715,6 @@ ifneq ($(XTENSA), 0)
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
@$(MD5SUM) test.bin
endif
+101 -50
View File
@@ -2,12 +2,10 @@
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
## Embedded
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
```go
@@ -37,62 +35,115 @@ The above program can be compiled and run without modification on an Arduino Uno
tinygo flash -target arduino examples/blinky1
```
## WebAssembly
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
TinyGo programs can run in Fastly Compute@Edge (https://developer.fastly.com/learning/compute/go/), Fermyon Spin (https://developer.fermyon.com/spin/go-components), wazero (https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
Here is a small TinyGo program for use by a WASI host application:
```go
package main
//go:wasm-module yourmodulename
//export add
func add(x, y uint32) uint32 {
return x + y
}
// main is required for the `wasi` target, even if it isn't used.
func main() {}
```
This compiles the above TinyGo program for use on any WASI runtime:
```shell
tinygo build -o main.wasm -target=wasi main.go
```
## Installation
See the [getting started instructions](https://tinygo.org/getting-started/) for information on how to install TinyGo, as well as how to run the TinyGo compiler using our Docker container.
## Supported targets
## Supported boards/targets
### Embedded
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
You can compile TinyGo programs for over 94 different microcontroller boards.
The following 94 microcontroller boards are currently supported:
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
* [Adafruit CLUE](https://www.adafruit.com/product/4500)
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
* [Adafruit Feather M0 Express](https://www.adafruit.com/product/3403)
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516)
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
* [Adafruit KB2040](https://www.adafruit.com/product/5302)
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
* [Arduino MKR WiFi 1010](https://store.arduino.cc/usa/mkr-wifi-1010)
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
* [Arduino Nano 33 BLE](https://store.arduino.cc/nano-33-ble)
* [Arduino Nano 33 BLE Sense](https://store.arduino.cc/nano-33-ble-sense)
* [Arduino Nano 33 IoT](https://store.arduino.cc/nano-33-iot)
* [Arduino Nano RP2040 Connect](https://store.arduino.cc/nano-rp2040-connect)
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
* [BBC micro:bit](https://microbit.org/)
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
* [blues wireless Swan](https://blues.io/products/swan/)
* [Digispark](http://digistump.com/products/1)
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
* [iLabs Challenger RP2040 LoRa](https://ilabs.se/product/challenger-rp2040-lora/)
* [M5Stack](https://docs.m5stack.com/en/core/basic)
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
* [MCH2022 badge](https://badge.team/docs/badges/mch2022/)
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
* [Nintendo Switch](https://www.nintendo.com/switch/)
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
* [Nordic Semiconductor pca10059](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
* [Pimoroni Tufty2040](https://shop.pimoroni.com/products/tufty-2040)
* [PineTime DevKit](https://www.pine64.org/pinetime/)
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
* [Seeed XIAO ESP32C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
* [ST Micro STM32F469 "Discovery"](https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/32f469idiscovery.html)
* [The Things Industries Generic Node Sensor Edition](https://www.genericnode.com/docs/sensor-edition/)
* [Waveshare RP2040-Zero](https://www.waveshare.com/wiki/RP2040-Zero)
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
### WebAssembly
TinyGo programs can be compiled for both WASM and WASI targets.
For more information, see https://tinygo.org/docs/guides/webassembly/
### Operating Systems
You can also compile programs for Linux, macOS, and Windows targets.
For more information:
- Linux https://tinygo.org/docs/guides/linux/
- macOS https://tinygo.org/docs/guides/macos/
- Windows https://tinygo.org/docs/guides/windows/
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
## Currently supported features:
+1 -19
View File
@@ -12,7 +12,6 @@ import (
"path/filepath"
"time"
wasm "github.com/aykevl/go-wasm"
"github.com/blakesmith/ar"
)
@@ -75,25 +74,8 @@ func makeArchive(arfile *os.File, objs []string) error {
fileIndex int
}{symbol.Name, i})
}
} else if dbg, err := wasm.Parse(objfile); err == nil {
for _, s := range dbg.Sections {
switch section := s.(type) {
case *wasm.SectionImport:
for _, ln := range section.Entries {
if ln.Kind != wasm.ExtKindFunction {
// Not a function
continue
}
symbolTable = append(symbolTable, struct {
name string
fileIndex int
}{ln.Field, i})
}
}
}
} else {
return fmt.Errorf("failed to open file %s as WASM, ELF or PE/COFF: %w", objpath, err)
return fmt.Errorf("failed to open file %s as ELF or PE/COFF: %w", objpath, err)
}
// Close file, to avoid issues with too many open files (especially on
+77 -53
View File
@@ -169,13 +169,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
SizeLevel: sizeLevel,
TinyGoVersion: goenv.Version,
Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(),
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
Debug: true,
}
// Load the target machine, which is the LLVM object that contains all
@@ -191,9 +190,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
lprogram, err := loader.Load(config, pkgName, config.ClangHeaders, types.Config{
Sizes: compiler.Sizes(machine),
})
if err != nil {
return BuildResult{}, err
}
result := BuildResult{
ModuleRoot: lprogram.MainPkg().Module.Dir,
MainDir: lprogram.MainPkg().Dir,
@@ -203,6 +199,9 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// If there is no module root, just the regular root.
result.ModuleRoot = lprogram.MainPkg().Root
}
if err != nil { // failed to load AST
return result, err
}
err = lprogram.Parse()
if err != nil {
return result, err
@@ -217,27 +216,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
var packageJobs []*compileJob
packageActionIDJobs := make(map[string]*compileJob)
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
if config.TestConfig.CompileTestBinary {
// The testing.testBinary is set to "1" when in a test.
// This is needed for testing.Testing() to work correctly.
if config.Options.GlobalValues["testing"] == nil {
config.Options.GlobalValues["testing"] = make(map[string]string)
}
config.Options.GlobalValues["testing"]["testBinary"] = "1"
}
var embedFileObjects []*compileJob
for _, pkg := range lprogram.Sorted() {
@@ -314,6 +305,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
actionID := packageAction{
ImportPath: pkg.ImportPath,
CompilerBuildID: string(compilerBuildID),
TinyGoVersion: goenv.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
@@ -344,10 +336,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
packageActionIDJobs[pkg.ImportPath] = packageActionIDJob
// Build the SSA for the given package.
ssaPkg := program.Package(pkg.Pkg)
ssaPkg.Build()
// Now create the job to actually build the package. It will exit early
// if the package is already compiled.
job := &compileJob{
@@ -606,7 +594,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
defer llvmBuf.Dispose()
return result, os.WriteFile(outpath, llvmBuf.Bytes(), 0666)
case ".bc":
buf := llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
var buf llvm.MemoryBuffer
if config.UseThinLTO() {
buf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
}
defer buf.Dispose()
return result, os.WriteFile(outpath, buf.Bytes(), 0666)
case ".ll":
@@ -628,7 +621,16 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
dependencies: []*compileJob{programJob},
result: objfile,
run: func(*compileJob) error {
llvmBuf := llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
var llvmBuf llvm.MemoryBuffer
if config.UseThinLTO() {
llvmBuf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
var err error
llvmBuf, err = machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
}
}
defer llvmBuf.Dispose()
return os.WriteFile(objfile, llvmBuf.Bytes(), 0666)
},
@@ -662,7 +664,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
job := &compileJob{
description: "compile extra file " + path,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(), config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(), config.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -680,7 +682,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
job := &compileJob{
description: "compile CGo file " + abspath,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, tmpdir, pkg.CFlags, config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, tmpdir, pkg.CFlags, config.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -739,34 +741,36 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
ldflags = append(ldflags, dependency.result)
}
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker.
ldflags = append(ldflags,
"-Xlink=/opt:lldlto="+strconv.Itoa(optLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
} else if config.GOOS() == "darwin" {
// Options for the ld64-compatible lld linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(optLevel),
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
} else {
// Options for the ELF linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(optLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
)
}
if config.CodeModel() != "default" {
ldflags = append(ldflags,
"-mllvm", "-code-model="+config.CodeModel())
}
if sizeLevel >= 2 {
// Workaround with roughly the same effect as
// https://reviews.llvm.org/D119342.
// Can hopefully be removed in LLVM 15.
ldflags = append(ldflags,
"-mllvm", "--rotation-max-header-size=0")
if config.UseThinLTO() {
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker.
ldflags = append(ldflags,
"-Xlink=/opt:lldlto="+strconv.Itoa(optLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
} else if config.GOOS() == "darwin" {
// Options for the ld64-compatible lld linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(optLevel),
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
} else {
// Options for the ELF linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(optLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
)
}
if config.CodeModel() != "default" {
ldflags = append(ldflags,
"-mllvm", "-code-model="+config.CodeModel())
}
if sizeLevel >= 2 {
// Workaround with roughly the same effect as
// https://reviews.llvm.org/D119342.
// Can hopefully be removed in LLVM 15.
ldflags = append(ldflags,
"-mllvm", "--rotation-max-header-size=0")
}
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(config.Target.Linker, ldflags...)
@@ -921,8 +925,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
case "nrf-dfu":
// special format for nrfutil for Nordic chips
tmphexpath := filepath.Join(tmpdir, "main.hex")
err := objcopy(result.Executable, tmphexpath, "hex")
if err != nil {
return result, err
}
result.Binary = filepath.Join(tmpdir, "main"+outext)
err = makeDFUFirmwareImage(config.Options, result.Executable, result.Binary)
err = makeDFUFirmwareImage(config.Options, tmphexpath, result.Binary)
if err != nil {
return result, err
}
@@ -1060,12 +1069,27 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
}
}
if config.GOOS() != "darwin" && !config.UseThinLTO() {
transform.ApplyFunctionSections(mod) // -ffunction-sections
}
// Insert values from -ldflags="-X ..." into the IR.
err = setGlobalValues(mod, config.Options.GlobalValues)
if err != nil {
return err
}
// Browsers cannot handle external functions that have type i64 because it
// cannot be represented exactly in JavaScript (JS only has doubles). To
// keep functions interoperable, pass int64 types as pointers to
// stack-allocated values.
if config.WasmAbi() == "js" {
err := transform.ExternalInt64AsPtr(mod, config)
if err != nil {
return err
}
}
// Optimization levels here are roughly the same as Clang, but probably not
// exactly.
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
+1 -1
View File
@@ -56,11 +56,11 @@ func TestClangAttributes(t *testing.T) {
{GOOS: "linux", GOARCH: "arm", GOARM: "6"},
{GOOS: "linux", GOARCH: "arm", GOARM: "7"},
{GOOS: "linux", GOARCH: "arm64"},
{GOOS: "linux", GOARCH: "mips"},
{GOOS: "darwin", GOARCH: "amd64"},
{GOOS: "darwin", GOARCH: "arm64"},
{GOOS: "windows", GOARCH: "amd64"},
{GOOS: "windows", GOARCH: "arm64"},
{GOOS: "wasip1", GOARCH: "wasm"},
} {
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
if options.GOARCH == "arm" {
+16 -8
View File
@@ -56,7 +56,7 @@ import (
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
@@ -67,6 +67,11 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
defer unlock()
ext := ".o"
if thinlto {
ext = ".bc"
}
// Create cache key for the dependencies file.
buf, err := json.Marshal(struct {
Path string
@@ -99,7 +104,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Obtain hashes of all the files listed as a dependency.
outpath, err := makeCFileCachePath(dependencies, depfileNameHash)
outpath, err := makeCFileCachePath(dependencies, depfileNameHash, ext)
if err == nil {
if _, err := os.Stat(outpath); err == nil {
return outpath, nil
@@ -112,7 +117,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
return "", err
}
objTmpFile, err := os.CreateTemp(goenv.Get("GOCACHE"), "tmp-*.bc")
objTmpFile, err := os.CreateTemp(goenv.Get("GOCACHE"), "tmp-*"+ext)
if err != nil {
return "", err
}
@@ -122,8 +127,11 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
return "", err
}
depTmpFile.Close()
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name(), "-flto=thin") // autogenerate dependencies
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
if thinlto {
flags = append(flags, "-flto=thin")
}
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
// If this is an assembly file (.s or .S, lowercase or uppercase), then
@@ -181,7 +189,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Move temporary object file to final location.
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash)
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash, ext)
if err != nil {
return "", err
}
@@ -196,7 +204,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
// Create a cache path (a path in GOCACHE) to store the output of a compiler
// job. This path is based on the dep file name (which is a hash of metadata
// including compiler flags) and the hash of all input files in the paths slice.
func makeCFileCachePath(paths []string, depfileNameHash string) (string, error) {
func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, error) {
// Hash all input files.
fileHashes := make(map[string]string, len(paths))
for _, path := range paths {
@@ -221,7 +229,7 @@ func makeCFileCachePath(paths []string, depfileNameHash string) (string, error)
outFileNameBuf := sha512.Sum512_224(buf)
cacheKey := hex.EncodeToString(outFileNameBuf[:])
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".bc")
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+ext)
return outpath, nil
}
+2 -19
View File
@@ -56,7 +56,6 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <optional>
#include <system_error>
using namespace clang;
using namespace clang::driver;
@@ -104,14 +103,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
VersionTuple Version;
if (Version.tryParse(A->getValue()))
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
Opts.DarwinTargetVariantSDKVersion = Version;
}
Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
Opts.Features = Args.getAllArgValues(OPT_target_feature);
@@ -131,12 +122,11 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Zlib)
.Case("zstd", llvm::DebugCompressionType::Zstd)
.Case("zlib", llvm::DebugCompressionType::Z)
.Default(llvm::DebugCompressionType::None);
}
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
@@ -199,7 +189,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
Opts.RelocationModel =
std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
@@ -225,8 +214,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Case("default", EmitDwarfUnwindType::Default);
}
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
return Success;
}
@@ -278,7 +265,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCTargetOptions MCOptions;
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
@@ -328,8 +314,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
TheTarget->createMCObjectFileInfo(Ctx, PIC));
if (Opts.DarwinTargetVariantTriple)
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
if (!Opts.DarwinTargetVariantSDKVersion.empty())
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
Ctx.setObjectFileInfo(MOFI.get());
if (Opts.SaveTemporaryLabels)
@@ -369,7 +353,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.MCNoWarn = Opts.NoWarn;
MCOptions.MCFatalWarnings = Opts.FatalWarnings;
MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
MCOptions.ABIName = Opts.TargetABI;
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
+1 -10
View File
@@ -82,7 +82,6 @@ struct AssemblerInvocation {
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
unsigned NoWarn : 1;
unsigned NoTypeCheck : 1;
unsigned IncrementalLinkerCompatible : 1;
unsigned EmbedBitcode : 1;
@@ -98,14 +97,7 @@ struct AssemblerInvocation {
/// Darwin target variant triple, the variant of the deployment target
/// for which the code is being compiled.
std::optional<llvm::Triple> DarwinTargetVariantTriple;
/// The version of the darwin target variant SDK which was used during the
/// compilation
llvm::VersionTuple DarwinTargetVariantSDKVersion;
/// The name of a file to use with \c .secure_log_unique directives.
std::string AsSecureLogFile;
llvm::Optional<llvm::Triple> DarwinTargetVariantTriple;
/// @}
public:
@@ -122,7 +114,6 @@ public:
NoExecStack = 0;
FatalWarnings = 0;
NoWarn = 0;
NoTypeCheck = 0;
IncrementalLinkerCompatible = 0;
Dwarf64 = 0;
DwarfVersion = 0;
+11 -7
View File
@@ -1,6 +1,7 @@
package builder
import (
"errors"
"fmt"
"github.com/tinygo-org/tinygo/compileopts"
@@ -23,14 +24,17 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
spec.OpenOCDCommands = options.OpenOCDCommands
}
major, minor, err := goenv.GetGorootVersion()
if err != nil {
return nil, err
goroot := goenv.Get("GOROOT")
if goroot == "" {
return nil, errors.New("cannot locate $GOROOT, please set it manually")
}
if major != 1 || minor < 18 || minor > 21 {
// 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.18 through 1.21, got go%d.%d", major, minor)
major, minor, err := goenv.GetGorootVersion(goroot)
if err != nil {
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
}
if major != 1 || minor < 18 || minor > 20 {
return nil, fmt.Errorf("requires go version 1.18 through 1.20, got go%d.%d", major, minor)
}
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
+1 -1
View File
@@ -23,7 +23,7 @@ type espImageSegment struct {
data []byte
}
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
// ESP8266 chip. This is a special purpose image format just for the ESP chip
// family, and is parsed by the on-chip mask ROM bootloader.
//
+1 -1
View File
@@ -134,7 +134,7 @@ func runJobs(job *compileJob, sema chan struct{}) error {
numRunningJobs--
<-sema
if jobRunnerDebug {
fmt.Println("## finished:", completed.description, "(time "+completed.duration.String()+")")
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
}
if completed.err != nil {
// Wait for any current jobs to finish.
-14
View File
@@ -3,39 +3,25 @@
// This file provides C wrappers for liblld.
#include <lld/Common/Driver.h>
#include <llvm/Support/Parallel.h>
extern "C" {
static void configure() {
#if _WIN64
// This is a hack to work around a hang in the LLD linker on Windows, with
// -DLLVM_ENABLE_THREADS=ON. It has a similar effect as the -threads=1
// linker flag, but with support for the COFF linker.
llvm::parallel::strategy = llvm::hardware_concurrency(1);
#endif
}
bool tinygo_link_elf(int argc, char **argv) {
configure();
std::vector<const char*> args(argv, argv + argc);
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_macho(int argc, char **argv) {
configure();
std::vector<const char*> args(argv, argv + argc);
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_mingw(int argc, char **argv) {
configure();
std::vector<const char*> args(argv, argv + argc);
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_wasm(int argc, char **argv) {
configure();
std::vector<const char*> args(argv, argv + argc);
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
}
+13 -103
View File
@@ -1,117 +1,27 @@
package builder
import (
"archive/zip"
"bytes"
"encoding/binary"
"encoding/json"
"os"
"fmt"
"io"
"os/exec"
"github.com/sigurn/crc16"
"github.com/tinygo-org/tinygo/compileopts"
)
// Structure of the manifest.json file.
type jsonManifest struct {
Manifest struct {
Application struct {
BinaryFile string `json:"bin_file"`
DataFile string `json:"dat_file"`
InitPacketData nrfInitPacket `json:"init_packet_data"`
} `json:"application"`
DFUVersion float64 `json:"dfu_version"` // yes, this is a JSON number, not a string
} `json:"manifest"`
}
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrfutil%2FUG%2Fnrfutil%2Fnrfutil_intro.html
// Structure of the init packet.
// Source:
// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/lib/sdk11/components/libraries/bootloader_dfu/dfu_init.h#L47-L57
type nrfInitPacket struct {
ApplicationVersion uint32 `json:"application_version"`
DeviceRevision uint16 `json:"device_revision"`
DeviceType uint16 `json:"device_type"`
FirmwareCRC16 uint16 `json:"firmware_crc16"`
SoftDeviceRequired []uint16 `json:"softdevice_req"` // this is actually a variable length array
}
// Create the init packet (the contents of application.dat).
func (p nrfInitPacket) createInitPacket() []byte {
buf := &bytes.Buffer{}
binary.Write(buf, binary.LittleEndian, p.DeviceType) // uint16_t device_type;
binary.Write(buf, binary.LittleEndian, p.DeviceRevision) // uint16_t device_rev;
binary.Write(buf, binary.LittleEndian, p.ApplicationVersion) // uint32_t app_version;
binary.Write(buf, binary.LittleEndian, uint16(len(p.SoftDeviceRequired))) // uint16_t softdevice_len;
binary.Write(buf, binary.LittleEndian, p.SoftDeviceRequired) // uint16_t softdevice[1];
binary.Write(buf, binary.LittleEndian, p.FirmwareCRC16)
return buf.Bytes()
}
// Make a Nordic DFU firmware image from an ELF file.
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
// Read ELF file as input and convert it to a binary image file.
_, data, err := extractROM(infile)
if err != nil {
return err
cmdLine := []string{"nrfutil", "pkg", "generate", "--hw-version", "52", "--sd-req", "0x0", "--debug-mode", "--application", infile, outfile}
if options.PrintCommands != nil {
options.PrintCommands(cmdLine[0], cmdLine[1:]...)
}
// Create the zip file in memory.
// It won't be very large anyway.
buf := &bytes.Buffer{}
w := zip.NewWriter(buf)
// Write the application binary to the zip file.
binw, err := w.Create("application.bin")
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
cmd.Stdout = io.Discard
err := cmd.Run()
if err != nil {
return err
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
}
_, err = binw.Write(data)
if err != nil {
return err
}
// Create the init packet.
initPacket := nrfInitPacket{
ApplicationVersion: 0xffff_ffff, // appears to be unused by the Adafruit bootloader
DeviceRevision: 0xffff, // DFU_DEVICE_REVISION_EMPTY
DeviceType: 0x0052, // ADAFRUIT_DEVICE_TYPE
FirmwareCRC16: crc16.Checksum(data, crc16.MakeTable(crc16.CRC16_CCITT_FALSE)),
SoftDeviceRequired: []uint16{0xfffe}, // DFU_SOFTDEVICE_ANY
}
// Write the init packet to the zip file.
datw, err := w.Create("application.dat")
if err != nil {
return err
}
_, err = datw.Write(initPacket.createInitPacket())
if err != nil {
return err
}
// Create the JSON manifest.
manifest := &jsonManifest{}
manifest.Manifest.Application.BinaryFile = "application.bin"
manifest.Manifest.Application.DataFile = "application.dat"
manifest.Manifest.Application.InitPacketData = initPacket
manifest.Manifest.DFUVersion = 0.5
// Write the JSON manifest to the file.
jsonw, err := w.Create("manifest.json")
if err != nil {
return err
}
enc := json.NewEncoder(jsonw)
enc.SetIndent("", " ")
err = enc.Encode(manifest)
if err != nil {
return err
}
// Finish the zip file.
err = w.Close()
if err != nil {
return err
}
return os.WriteFile(outfile, buf.Bytes(), 0o666)
return nil
}
+27 -105
View File
@@ -75,7 +75,6 @@ func (ps *packageSize) RAM() uint64 {
type addressLine struct {
Address uint64
Length uint64 // length of this chunk
Align uint64 // (maximum) alignment of this line
File string // file path as stored in DWARF
IsVariable bool // true if this is a variable (or constant), false if it is code
}
@@ -87,7 +86,6 @@ type memorySection struct {
Type memoryType
Address uint64
Size uint64
Align uint64
}
type memoryType int
@@ -119,13 +117,13 @@ var (
// alloc: heap allocations during init interpretation
// pack: data created when storing a constant in an interface for example
// string: buffer behind strings
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|pack|string)(\.[0-9]+)?$`)
packageSymbolRegexp = regexp.MustCompile(`\$(alloc|embedfsfiles|embedfsslice|embedslice|pack|string)(\.[0-9]+)?$`)
)
// readProgramSizeFromDWARF reads the source location for each line of code and
// each variable in the program, as far as this is stored in the DWARF debug
// information.
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64, skipTombstone bool) ([]addressLine, error) {
func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone bool) ([]addressLine, error) {
r := data.Reader()
var lines []*dwarf.LineFile
var addresses []addressLine
@@ -197,7 +195,6 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64
line := addressLine{
Address: prevLineEntry.Address + codeOffset,
Length: lineEntry.Address - prevLineEntry.Address,
Align: codeAlignment,
File: prevLineEntry.File.Name,
}
if line.Length != 0 {
@@ -222,9 +219,20 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64
// Try to parse the location. While this could in theory be a very
// complex expression, usually it's just a DW_OP_addr opcode
// followed by an address.
addr, err := readDWARFConstant(r.AddressSize(), location.Val.([]uint8))
if err != nil {
continue // ignore the error, we don't know what to do with it
locationCode := location.Val.([]uint8)
if locationCode[0] != 3 { // DW_OP_addr
continue
}
var addr uint64
switch len(locationCode) {
case 1 + 2:
addr = uint64(binary.LittleEndian.Uint16(locationCode[1:]))
case 1 + 4:
addr = uint64(binary.LittleEndian.Uint32(locationCode[1:]))
case 1 + 8:
addr = binary.LittleEndian.Uint64(locationCode[1:])
default:
continue // unknown address
}
// Parse the type of the global variable, which (importantly)
@@ -235,16 +243,9 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64
return nil, err
}
// Read alignment, if it's stored as part of the debug information.
var alignment uint64
if attr := e.AttrField(dwarf.AttrAlignment); attr != nil {
alignment = uint64(attr.Val.(int64))
}
addresses = append(addresses, addressLine{
Address: addr,
Length: uint64(typ.Size()),
Align: alignment,
File: lines[file.Val.(int64)].Name,
IsVariable: true,
})
@@ -255,52 +256,6 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64
return addresses, nil
}
// Parse a DWARF constant. For addresses, this is usually a very simple
// expression.
func readDWARFConstant(addressSize int, bytecode []byte) (uint64, error) {
var addr uint64
for len(bytecode) != 0 {
op := bytecode[0]
bytecode = bytecode[1:]
switch op {
case 0x03: // DW_OP_addr
switch addressSize {
case 2:
addr = uint64(binary.LittleEndian.Uint16(bytecode))
case 4:
addr = uint64(binary.LittleEndian.Uint32(bytecode))
case 8:
addr = binary.LittleEndian.Uint64(bytecode)
default:
panic("unexpected address size")
}
bytecode = bytecode[addressSize:]
case 0x23: // DW_OP_plus_uconst
offset, n := readULEB128(bytecode)
addr += offset
bytecode = bytecode[n:]
default:
return 0, fmt.Errorf("unknown DWARF opcode: 0x%x", op)
}
}
return addr, nil
}
// Source: https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
func readULEB128(buf []byte) (result uint64, n int) {
var shift uint8
for {
b := buf[n]
n++
result |= uint64(b&0x7f) << shift
if b&0x80 == 0 {
break
}
shift += 7
}
return
}
// Read a MachO object file and return a line table.
// Also return an index from symbol name to start address in the line table.
func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error) {
@@ -322,7 +277,7 @@ func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error
if err != nil {
return nil, nil, err
}
lines, err := readProgramSizeFromDWARF(dwarf, 0, 0, false)
lines, err := readProgramSizeFromDWARF(dwarf, 0, false)
if err != nil {
return nil, nil, err
}
@@ -379,15 +334,10 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Load the binary file, which could be in a number of file formats.
var sections []memorySection
if file, err := elf.NewFile(f); err == nil {
var codeAlignment uint64
switch file.Machine {
case elf.EM_ARM:
codeAlignment = 4 // usually 2, but can be 4
}
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
addresses, err = readProgramSizeFromDWARF(data, 0, codeAlignment, true)
addresses, err = readProgramSizeFromDWARF(data, 0, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -421,7 +371,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
if section.Flags&elf.SHF_ALLOC == 0 {
continue
}
if packageSymbolRegexp.MatchString(symbol.Name) || symbol.Name == "__isr_vector" {
if packageSymbolRegexp.MatchString(symbol.Name) {
addresses = append(addresses, addressLine{
Address: symbol.Value,
Length: symbol.Size,
@@ -445,7 +395,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
Align: section.Addralign,
Type: memoryStack,
})
} else {
@@ -453,7 +402,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
Align: section.Addralign,
Type: memoryBSS,
})
}
@@ -462,7 +410,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
Align: section.Addralign,
Type: memoryCode,
})
} else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_WRITE != 0 {
@@ -470,7 +417,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
Align: section.Addralign,
Type: memoryData,
})
} else if section.Type == elf.SHT_PROGBITS {
@@ -478,7 +424,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
Align: section.Addralign,
Type: memoryROData,
})
}
@@ -505,7 +450,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Align: uint64(section.Align),
Type: memoryCode,
})
} else if sectionType == 1 { // S_ZEROFILL
@@ -513,7 +457,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Align: uint64(section.Align),
Type: memoryBSS,
})
} else if segment.Maxprot&0b011 == 0b001 { // --r (read-only data)
@@ -521,7 +464,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Align: uint64(section.Align),
Type: memoryROData,
})
} else {
@@ -529,7 +471,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Align: uint64(section.Align),
Type: memoryData,
})
}
@@ -613,7 +554,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
addresses, err = readProgramSizeFromDWARF(data, 0, 0, true)
addresses, err = readProgramSizeFromDWARF(data, 0, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -685,7 +626,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
addresses, err = readProgramSizeFromDWARF(data, codeOffset, 0, true)
addresses, err = readProgramSizeFromDWARF(data, codeOffset, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -845,18 +786,10 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
if addr < line.Address {
// There is a gap: there is a space between the current and the
// previous line entry.
// Check whether this is caused by alignment requirements.
addrAligned := (addr + line.Align - 1) &^ (line.Align - 1)
if line.Align > 1 && addrAligned >= line.Address {
// It is, assume that's what causes the gap.
addSize("(padding)", line.Address-addr, true)
} else {
addSize("(unknown)", line.Address-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (gap), alignment=%d\n", addr, line.Address, line.Address-addr, line.Align)
}
addSize("(unknown)", line.Address-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (gap)\n", addr, line.Address, line.Address-addr)
}
addr = line.Address
}
if addr > line.Address+line.Length {
// The current line is already covered by a previous line entry.
@@ -878,16 +811,9 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
}
if addr < sectionEnd {
// There is a gap at the end of the section.
addrAligned := (addr + section.Align - 1) &^ (section.Align - 1)
if section.Align > 1 && addrAligned >= sectionEnd {
// The gap is caused by the section alignment.
// For example, if a .rodata section ends with a non-aligned string.
addSize("(padding)", sectionEnd-addr, true)
} else {
addSize("(unknown)", sectionEnd-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (end), alignment=%d\n", addr, sectionEnd, sectionEnd-addr, section.Align)
}
addSize("(unknown)", sectionEnd-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %5d: unknown (end)\n", addr, sectionEnd, sectionEnd-addr)
}
}
}
@@ -903,13 +829,9 @@ func findPackagePath(path string, packagePathMap map[string]string) string {
// package, with a "C" prefix. For example: "C compiler-rt" for the
// compiler runtime library from LLVM.
packagePath = "C " + strings.Split(strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")), string(os.PathSeparator))[1]
} else if strings.HasPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project")) {
packagePath = "C compiler-rt"
} else if packageSymbolRegexp.MatchString(path) {
// Parse symbol names like main$alloc or runtime$string.
packagePath = path[:strings.LastIndex(path, "$")]
} else if path == "__isr_vector" {
packagePath = "C interrupt vector"
} else if path == "<Go type>" {
packagePath = "Go types"
} else if path == "<Go interface assert>" {
-92
View File
@@ -1,92 +0,0 @@
package builder
import (
"runtime"
"testing"
"time"
"github.com/tinygo-org/tinygo/compileopts"
)
var sema = make(chan struct{}, runtime.NumCPU())
type sizeTest struct {
target string
path string
codeSize uint64
rodataSize uint64
dataSize uint64
bssSize uint64
}
// Test whether code and data size is as expected for the given targets.
// This tests both the logic of loadProgramSize and checks that code size
// doesn't change unintentionally.
//
// If you find that code or data size is reduced, then great! You can reduce the
// number in this test.
// If you find that the code or data size is increased, take a look as to why
// this is. It could be due to an update (LLVM version, Go version, etc) which
// is fine, but it could also mean that a recent change introduced this size
// increase. If so, please consider whether this new feature is indeed worth the
// size increase for all users.
func TestBinarySize(t *testing.T) {
if runtime.GOOS == "linux" && !hasBuiltinTools {
// Debian LLVM packages are modified a bit and tend to produce
// different machine code. Ideally we'd fix this (with some attributes
// or something?), but for now skip it.
t.Skip("Skip: using external LLVM version so binary size might differ")
}
// This is a small number of very diverse targets that we want to test.
tests := []sizeTest{
// microcontrollers
{"hifive1b", "examples/echo", 4568, 280, 0, 2252},
{"microbit", "examples/serial", 2728, 388, 8, 2256},
{"wioterminal", "examples/pininterrupt", 5996, 1484, 116, 6816},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
// output varies by binaryen version.
}
for _, tc := range tests {
tc := tc
t.Run(tc.target+"/"+tc.path, func(t *testing.T) {
t.Parallel()
// Build the binary.
options := compileopts.Options{
Target: tc.target,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(tc.path, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
// Check whether the size of the binary matches the expected size.
sizes, err := loadProgramSize(result.Executable, nil)
if err != nil {
t.Fatal("could not read program size:", err)
}
if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize {
t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path)
t.Errorf(" code rodata data bss")
t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize)
t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS)
}
})
}
}
+19 -9
View File
@@ -75,10 +75,19 @@ type bitfieldInfo struct {
}
// cgoAliases list type aliases between Go and C, for types that are equivalent
// in both languages.
// in both languages. See addTypeAliases.
var cgoAliases = map[string]string{
"float": "float32",
"double": "float64",
"C.int8_t": "int8",
"C.int16_t": "int16",
"C.int32_t": "int32",
"C.int64_t": "int64",
"C.uint8_t": "uint8",
"C.uint16_t": "uint16",
"C.uint32_t": "uint32",
"C.uint64_t": "uint64",
"C.uintptr_t": "uintptr",
"C.float": "float32",
"C.double": "float64",
}
// builtinAliases are handled specially because they only exist on the Go side
@@ -302,11 +311,10 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
// Process CGo imports for each file.
for i, f := range files {
cf := p.newCGoFile(f, i)
// These types are aliased with the corresponding types in C. For
// example, float in C is always float32 in Go.
for name := range cgoAliases {
cf.names[name] = clangCursor{}
}
// Float and double are aliased, meaning that C.float is the same thing
// as float32 in Go.
cf.names["float"] = clangCursor{}
cf.names["double"] = clangCursor{}
// Now read all the names (identifies) that C defines in the header
// snippet.
cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
@@ -1121,7 +1129,9 @@ func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
// getASTDeclName will declare the given C AST node (if not already defined) and
// will return its name, in the form of C.foo.
func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string {
if alias := cgoAliases[name]; alias != "" {
// Some types are defined in stdint.h and map directly to a particular Go
// type.
if alias := cgoAliases["C."+name]; alias != "" {
return alias
}
node := f.getASTDeclNode(name, found, iscall)
+2 -16
View File
@@ -60,7 +60,6 @@ CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c);
unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c);
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
@@ -654,19 +653,8 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
// Strip typedefs, if any.
underlyingType := typ
if underlyingType.kind == C.CXType_Elaborated {
// Starting with LLVM 16, the elaborated type is used for more types.
// According to the Clang documentation, the elaborated type has no
// semantic meaning so can be stripped (it is used to better convey type
// name information).
// Source:
// https://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html#details
// > The type itself is always "sugar", used to express what was written
// > in the source code but containing no additional semantic information.
underlyingType = C.clang_Type_getNamedType(underlyingType)
}
if underlyingType.kind == C.CXType_Typedef {
c := C.tinygo_clang_getTypeDeclaration(underlyingType)
c := C.tinygo_clang_getTypeDeclaration(typ)
underlyingType = C.tinygo_clang_getTypedefDeclUnderlyingType(c)
// TODO: support a chain of typedefs. At the moment, it seems to get
// stuck in an endless loop when trying to get to the most underlying
@@ -800,8 +788,6 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
return f.makeASTType(underlying, pos)
case C.CXType_Enum:
return f.makeASTType(underlying, pos)
case C.CXType_Typedef:
return f.makeASTType(underlying, pos)
default:
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
@@ -820,7 +806,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
// makeASTRecordType will create an appropriate error.
cgoRecordPrefix = "record_"
}
if name == "" || C.tinygo_clang_Cursor_isAnonymous(cursor) != 0 {
if name == "" {
// Anonymous record, probably inside a typedef.
location := f.getUniqueLocationID(pos, cursor)
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build !byollvm && llvm15
//go:build !byollvm && !llvm14
package cgo
-21
View File
@@ -1,21 +0,0 @@
//go:build !byollvm && !llvm14 && !llvm15
package cgo
// As of 2023-05-05, there is a packaging issue on Debian:
// https://github.com/llvm/llvm-project/issues/62199
// A workaround is to fix this locally, using something like this:
//
// ln -sf ../../x86_64-linux-gnu/libclang-16.so.1 /usr/lib/llvm-16/lib/libclang.so
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-16/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@16/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
#cgo freebsd CFLAGS: -I/usr/local/llvm16/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
*/
import "C"
+1 -5
View File
@@ -77,10 +77,6 @@ CXType tinygo_clang_getEnumDeclIntegerType(CXCursor c) {
return clang_getEnumDeclIntegerType(c);
}
unsigned tinygo_clang_Cursor_isAnonymous(CXCursor c) {
return clang_Cursor_isAnonymous(c);
}
unsigned tinygo_clang_Cursor_isBitField(CXCursor c) {
return clang_Cursor_isBitField(c);
}
}
-1
View File
@@ -142,7 +142,6 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-L([^@\-].*)`),
re(`-O`),
re(`-O([^@\-].*)`),
re(`--export=([^@\-].*)`),
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?openmp(-simd)?`),
re(`-fsanitize=([^@\-].*)`),
-1
View File
@@ -108,7 +108,6 @@ var goodLinkerFlags = [][]string{
{"-Fbar"},
{"-lbar"},
{"-Lbar"},
{"--export=my_symbol"},
{"-fpic"},
{"-fno-pic"},
{"-fPIC"},
-8
View File
@@ -22,12 +22,8 @@ import "C"
// #warning another warning
import "C"
// #include <stdint.h>
import "C"
// Make sure that errors for the following lines won't change with future
// additions to the CGo preamble.
//
//line errors.go:100
var (
// constant too large
@@ -42,8 +38,4 @@ var (
_ byte = C.SOME_CONST_3
_ = C.SOME_CONST_4
// This must result in a type error. Previously, TinyGo would allow this
// code (which is not allowed by upstream Go).
_ int8 = C.int8_t(5)
)
+2 -5
View File
@@ -11,7 +11,6 @@
// testdata/errors.go:108: undefined: C.SOME_CONST_1
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
// testdata/errors.go:112: undefined: C.SOME_CONST_4
// testdata/errors.go:116: cannot use C.int8_t(5) (constant 5 of type C.schar) as int8 value in variable declaration
package main
@@ -52,12 +51,10 @@ type (
C.longlong int64
C.ulonglong uint64
)
type C.struct_point_t struct {
type C._Ctype_struct___0 struct {
x C.int
y C.int
}
type C.point_t = C.struct_point_t
type C.point_t = C._Ctype_struct___0
const C.SOME_CONST_3 = 1234
type C.int8_t = C.schar
+36 -34
View File
@@ -38,11 +38,11 @@ type (
C.ulonglong uint64
)
type C.myint = C.int
type C.struct_point2d_t struct {
type C._Ctype_struct___0 struct {
x C.int
y C.int
}
type C.point2d_t = C.struct_point2d_t
type C.point2d_t = C._Ctype_struct___0
type C.struct_point3d struct {
x C.int
y C.int
@@ -55,19 +55,21 @@ type C.struct_type1 struct {
___type C.int
}
type C.struct_type2 struct{ _type C.int }
type C.union_union1_t struct{ i C.int }
type C.union1_t = C.union_union1_t
type C.union_union3_t struct{ $union uint64 }
type C._Ctype_union___1 struct{ i C.int }
type C.union1_t = C._Ctype_union___1
type C._Ctype_union___2 struct{ $union uint64 }
func (union *C.union_union3_t) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
func (union *C.union_union3_t) unionfield_d() *float64 {
func (union *C._Ctype_union___2) unionfield_i() *C.int {
return (*C.int)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___2) unionfield_d() *float64 {
return (*float64)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union3_t) unionfield_s() *C.short {
func (union *C._Ctype_union___2) unionfield_s() *C.short {
return (*C.short)(unsafe.Pointer(&union.$union))
}
type C.union3_t = C.union_union3_t
type C.union3_t = C._Ctype_union___2
type C.union_union2d struct{ $union [2]uint64 }
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
@@ -76,50 +78,50 @@ func (union *C.union_union2d) unionfield_d() *[2]float64 {
}
type C.union2d_t = C.union_union2d
type C.union_unionarray_t struct{ arr [10]C.uchar }
type C.unionarray_t = C.union_unionarray_t
type C._Ctype_union___0 struct{ $union [3]uint32 }
type C._Ctype_union___3 struct{ arr [10]C.uchar }
type C.unionarray_t = C._Ctype_union___3
type C._Ctype_union___5 struct{ $union [3]uint32 }
func (union *C._Ctype_union___0) unionfield_area() *C.point2d_t {
func (union *C._Ctype_union___5) unionfield_area() *C.point2d_t {
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___0) unionfield_solid() *C.point3d_t {
func (union *C._Ctype_union___5) unionfield_solid() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
type C.struct_struct_nested_t struct {
type C._Ctype_struct___4 struct {
begin C.point2d_t
end C.point2d_t
tag C.int
coord C._Ctype_union___0
coord C._Ctype_union___5
}
type C.struct_nested_t = C.struct_struct_nested_t
type C.union_union_nested_t struct{ $union [2]uint64 }
type C.struct_nested_t = C._Ctype_struct___4
type C._Ctype_union___6 struct{ $union [2]uint64 }
func (union *C.union_union_nested_t) unionfield_point() *C.point3d_t {
func (union *C._Ctype_union___6) unionfield_point() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union_nested_t) unionfield_array() *C.unionarray_t {
func (union *C._Ctype_union___6) unionfield_array() *C.unionarray_t {
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union_nested_t) unionfield_thing() *C.union3_t {
func (union *C._Ctype_union___6) unionfield_thing() *C.union3_t {
return (*C.union3_t)(unsafe.Pointer(&union.$union))
}
type C.union_nested_t = C.union_union_nested_t
type C.union_nested_t = C._Ctype_union___6
type C.enum_option = C.int
type C.option_t = C.enum_option
type C.enum_option2_t = C.uint
type C.option2_t = C.enum_option2_t
type C.struct_types_t struct {
type C._Ctype_enum___7 = C.uint
type C.option2_t = C._Ctype_enum___7
type C._Ctype_struct___8 struct {
f float32
d float64
ptr *C.int
}
type C.types_t = C.struct_types_t
type C.types_t = C._Ctype_struct___8
type C.myIntArray = [10]C.int
type C.struct_bitfield_t struct {
type C._Ctype_struct___9 struct {
start C.uchar
__bitfield_1 C.uchar
@@ -127,21 +129,21 @@ type C.struct_bitfield_t struct {
e C.uchar
}
func (s *C.struct_bitfield_t) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
func (s *C.struct_bitfield_t) set_bitfield_a(value C.uchar) {
func (s *C._Ctype_struct___9) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
func (s *C._Ctype_struct___9) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
}
func (s *C.struct_bitfield_t) bitfield_b() C.uchar {
func (s *C._Ctype_struct___9) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1
}
func (s *C.struct_bitfield_t) set_bitfield_b(value C.uchar) {
func (s *C._Ctype_struct___9) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
}
func (s *C.struct_bitfield_t) bitfield_c() C.uchar {
func (s *C._Ctype_struct___9) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6
}
func (s *C.struct_bitfield_t) set_bitfield_c(value C.uchar,
func (s *C._Ctype_struct___9) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type C.bitfield_t = C.struct_bitfield_t
type C.bitfield_t = C._Ctype_struct___9
+40 -11
View File
@@ -75,7 +75,8 @@ func (c *Config) GOARM() string {
// BuildTags returns the complete list of build tags used during this build.
func (c *Config) BuildTags() []string {
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
targetTags := filterTags(c.Target.BuildTags, c.Options.Tags)
tags := append(targetTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i))
}
@@ -190,6 +191,14 @@ func (c *Config) StackSize() uint64 {
return c.Target.DefaultStackSize
}
// UseThinLTO returns whether ThinLTO should be used for the given target.
func (c *Config) UseThinLTO() bool {
// All architectures support ThinLTO now. However, this code is kept for the
// time being in case there are regressions. The non-ThinLTO code support
// should be removed when it is proven to work reliably.
return true
}
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
@@ -492,6 +501,11 @@ func (c *Config) RelocationModel() string {
return "static"
}
// WasmAbi returns the WASM ABI which is specified in the target JSON file.
func (c *Config) WasmAbi() string {
return c.Target.WasmAbi
}
// EmulatorName is a shorthand to get the command for this emulator, something
// like qemu-system-arm or simavr.
func (c *Config) EmulatorName() string {
@@ -535,14 +549,29 @@ func (c *Config) Emulator(format, binary string) ([]string, error) {
type TestConfig struct {
CompileTestBinary bool
CompileOnly bool
Verbose bool
Short bool
RunRegexp string
SkipRegexp string
Count *int
BenchRegexp string
BenchTime string
BenchMem bool
Shuffle string
// TODO: Filter the test functions to run, include verbose flag, etc
}
// filterTags removes predefined build tags for a target if a conflicting option
// is provided by the user.
func filterTags(targetTags []string, userTags []string) []string {
var filtered []string
for _, t := range targetTags {
switch {
case strings.HasPrefix(t, "runtime_memhash_"):
overridden := false
for _, ut := range userTags {
if strings.HasPrefix(ut, "runtime_memhash_") {
overridden = true
break
}
}
if !overridden {
filtered = append(filtered, t)
}
default:
filtered = append(filtered, t)
}
}
return filtered
}
+132
View File
@@ -0,0 +1,132 @@
package compileopts
import (
"fmt"
"strings"
"testing"
)
func TestBuildTags(t *testing.T) {
tests := []struct {
targetTags []string
userTags []string
result []string
}{
{
targetTags: []string{},
userTags: []string{},
result: []string{
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
},
},
{
targetTags: []string{"bear"},
userTags: []string{},
result: []string{
"bear",
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
},
},
{
targetTags: []string{},
userTags: []string{"cat"},
result: []string{
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
"cat",
},
},
{
targetTags: []string{"bear"},
userTags: []string{"cat"},
result: []string{
"bear",
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
"cat",
},
},
{
targetTags: []string{"bear", "runtime_memhash_leveldb"},
userTags: []string{"cat"},
result: []string{
"bear",
"runtime_memhash_leveldb",
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
"cat",
},
},
{
targetTags: []string{"bear", "runtime_memhash_leveldb"},
userTags: []string{"cat", "runtime_memhash_leveldb"},
result: []string{
"bear",
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
"cat",
"runtime_memhash_leveldb",
},
},
{
targetTags: []string{"bear", "runtime_memhash_leveldb"},
userTags: []string{"cat", "runtime_memhash_sip"},
result: []string{
"bear",
"tinygo",
"math_big_pure_go",
"gc.conservative",
"scheduler.none",
"serial.none",
"cat",
"runtime_memhash_sip",
},
},
}
for _, tc := range tests {
tt := tc
t.Run(fmt.Sprintf("%s+%s", strings.Join(tt.targetTags, ","), strings.Join(tt.userTags, ",")), func(t *testing.T) {
c := &Config{
Target: &TargetSpec{
BuildTags: tt.targetTags,
},
Options: &Options{
Tags: tt.userTags,
},
}
res := c.BuildTags()
if len(res) != len(tt.result) {
t.Errorf("expected %d tags, got %d", len(tt.result), len(res))
}
for i, tag := range tt.result {
if tag != res[i] {
t.Errorf("tag %d: expected %s, got %s", i, tt.result[i], tag)
}
}
})
}
}
-1
View File
@@ -35,7 +35,6 @@ type Options struct {
PrintIR bool
DumpSSA bool
VerifyIR bool
SkipDWARF bool
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
+47 -75
View File
@@ -23,45 +23,46 @@ import (
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct {
Inherits []string `json:"inherits,omitempty"`
Triple string `json:"llvm-target,omitempty"`
CPU string `json:"cpu,omitempty"`
ABI string `json:"target-abi,omitempty"` // rougly equivalent to -mabi= flag
Features string `json:"features,omitempty"`
GOOS string `json:"goos,omitempty"`
GOARCH string `json:"goarch,omitempty"`
BuildTags []string `json:"build-tags,omitempty"`
GC string `json:"gc,omitempty"`
Scheduler string `json:"scheduler,omitempty"`
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
Linker string `json:"linker,omitempty"`
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc,omitempty"`
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
CFlags []string `json:"cflags,omitempty"`
LDFlags []string `json:"ldflags,omitempty"`
LinkerScript string `json:"linkerscript,omitempty"`
ExtraFiles []string `json:"extra-files,omitempty"`
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
Emulator string `json:"emulator,omitempty"`
FlashCommand string `json:"flash-command,omitempty"`
GDB []string `json:"gdb,omitempty"`
PortReset string `json:"flash-1200-bps-reset,omitempty"`
SerialPort []string `json:"serial-port,omitempty"` // serial port IDs in the form "vid:pid"
FlashMethod string `json:"flash-method,omitempty"`
FlashVolume []string `json:"msd-volume-name,omitempty"`
FlashFilename string `json:"msd-firmware-name,omitempty"`
UF2FamilyID string `json:"uf2-family-id,omitempty"`
BinaryFormat string `json:"binary-format,omitempty"`
OpenOCDInterface string `json:"openocd-interface,omitempty"`
OpenOCDTarget string `json:"openocd-target,omitempty"`
OpenOCDTransport string `json:"openocd-transport,omitempty"`
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device,omitempty"`
CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"`
Inherits []string `json:"inherits"`
Triple string `json:"llvm-target"`
CPU string `json:"cpu"`
ABI string `json:"target-abi"` // rougly equivalent to -mabi= flag
Features string `json:"features"`
GOOS string `json:"goos"`
GOARCH string `json:"goarch"`
BuildTags []string `json:"build-tags"`
GC string `json:"gc"`
Scheduler string `json:"scheduler"`
Serial string `json:"serial"` // which serial output to use (uart, usb, none)
Linker string `json:"linker"`
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc"`
AutoStackSize *bool `json:"automatic-stack-size"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size"` // Default stack size if the size couldn't be determined at compile time.
CFlags []string `json:"cflags"`
LDFlags []string `json:"ldflags"`
LinkerScript string `json:"linkerscript"`
ExtraFiles []string `json:"extra-files"`
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
Emulator string `json:"emulator"`
FlashCommand string `json:"flash-command"`
GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"`
SerialPort []string `json:"serial-port"` // serial port IDs in the form "vid:pid"
FlashMethod string `json:"flash-method"`
FlashVolume string `json:"msd-volume-name"`
FlashFilename string `json:"msd-firmware-name"`
UF2FamilyID string `json:"uf2-family-id"`
BinaryFormat string `json:"binary-format"`
OpenOCDInterface string `json:"openocd-interface"`
OpenOCDTarget string `json:"openocd-target"`
OpenOCDTransport string `json:"openocd-transport"`
OpenOCDCommands []string `json:"openocd-commands"`
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device"`
CodeModel string `json:"code-model"`
RelocationModel string `json:"relocation-model"`
WasmAbi string `json:"wasm-abi"`
}
// overrideProperties overrides all properties that are set in child into itself using reflection.
@@ -191,15 +192,12 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
default:
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
}
case "wasm":
llvmarch = "wasm32"
default:
llvmarch = options.GOARCH
}
llvmvendor := "unknown"
llvmos := options.GOOS
switch llvmos {
case "darwin":
if llvmos == "darwin" {
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
// to iOS!
llvmos = "macosx10.12.0"
@@ -210,8 +208,6 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
llvmos = "macosx11.0.0"
}
llvmvendor = "apple"
case "wasip1":
llvmos = "wasi"
}
// Target triples (which actually have four components, but are called
// triples for historical reasons) have the form:
@@ -281,20 +277,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
}
case "arm64":
spec.CPU = "generic"
if goos == "darwin" {
spec.Features = "+neon"
} else { // windows, linux
spec.Features = "+neon,-fmv"
}
case "wasm":
spec.CPU = "generic"
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
spec.CFlags = append(spec.CFlags,
"-mbulk-memory",
"-mnontrapping-fptoint",
"-msign-ext",
)
spec.Features = "+neon"
case "mips":
spec.CPU = "mips32r2"
spec.Features = "+mips32r2,-noabicalls"
}
if goos == "darwin" {
spec.Linker = "ld.lld"
@@ -338,22 +324,6 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
"--no-insert-timestamp",
"--no-dynamicbase",
)
} else if goos == "wasip1" {
spec.GC = "" // use default GC
spec.Scheduler = "asyncify"
spec.Linker = "wasm-ld"
spec.RTLib = "compiler-rt"
spec.Libc = "wasi-libc"
spec.DefaultStackSize = 1024 * 32 // 32kB
spec.LDFlags = append(spec.LDFlags,
"--stack-first",
"--no-demangle",
)
spec.Emulator = "wasmtime --mapdir=/tmp::{tmpDir} {}"
spec.ExtraFiles = append(spec.ExtraFiles,
"src/runtime/asm_tinygowasm.S",
"src/internal/task/task_asyncify_wasm.S",
)
} else {
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
}
@@ -383,6 +353,8 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
spec.Emulator = "qemu-arm {}"
case "arm64":
spec.Emulator = "qemu-aarch64 {}"
case "mips":
spec.Emulator = "qemu-mips {}"
}
}
}
+10 -10
View File
@@ -13,8 +13,8 @@ import (
func (b *builder) createAtomicOp(name string) llvm.Value {
switch name {
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
ptr := b.getValue(b.fn.Params[0])
val := b.getValue(b.fn.Params[1])
if strings.HasPrefix(b.Triple, "avr") {
// AtomicRMW does not work on AVR as intended:
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
@@ -33,8 +33,8 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
// Return the new value, not the original value returned by atomicrmw.
return b.CreateAdd(oldVal, val, "")
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))
ptr := b.getValue(b.fn.Params[0])
val := b.getValue(b.fn.Params[1])
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
if isPointer {
// atomicrmw only supports integers, so cast to an integer.
@@ -48,21 +48,21 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
}
return oldVal
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
old := b.getValue(b.fn.Params[1], getPos(b.fn))
newVal := b.getValue(b.fn.Params[2], getPos(b.fn))
ptr := b.getValue(b.fn.Params[0])
old := b.getValue(b.fn.Params[1])
newVal := b.getValue(b.fn.Params[2])
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
swapped := b.CreateExtractValue(tuple, 1, "")
return swapped
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
ptr := b.getValue(b.fn.Params[0])
val := b.CreateLoad(b.getLLVMType(b.fn.Signature.Results().At(0).Type()), ptr, "")
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
return val
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
ptr := b.getValue(b.fn.Params[0])
val := b.getValue(b.fn.Params[1])
if strings.HasPrefix(b.Triple, "avr") {
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
vType := val.Type()
+2 -6
View File
@@ -36,11 +36,7 @@ const (
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
// createRuntimeInvoke instead.
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
member := b.program.ImportedPackage("runtime").Members[fnName]
if member == nil {
panic("unknown runtime call: " + fnName)
}
fn := member.(*ssa.Function)
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
fnType, llvmFn := b.getFunction(fn)
if llvmFn.IsNil() {
panic("trying to call non-existent function: " + fn.RelString(nil))
@@ -233,7 +229,7 @@ func extractSubfield(t types.Type, field int) types.Type {
}
}
// flattenAggregateTypeOffsets returns the offsets from the start of an object of
// flattenAggregateTypeOffset returns the offsets from the start of an object of
// type t if this object were flattened like in flattenAggregate. Used together
// with flattenAggregate to know the start indices of each value in the
// non-flattened object.
+8 -8
View File
@@ -14,7 +14,7 @@ import (
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().Underlying().(*types.Chan).Elem()))
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
bufSize := b.getValue(expr.Size, getPos(expr))
bufSize := b.getValue(expr.Size)
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
if bufSize.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
bufSize = b.CreateZExt(bufSize, b.uintptrType, "")
@@ -27,8 +27,8 @@ func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
// createChanSend emits a pseudo chan send operation. It is lowered to the
// actual channel send operation during goroutine lowering.
func (b *builder) createChanSend(instr *ssa.Send) {
ch := b.getValue(instr.Chan, getPos(instr))
chanValue := b.getValue(instr.X, getPos(instr))
ch := b.getValue(instr.Chan)
chanValue := b.getValue(instr.X)
// store value-to-send
valueType := b.getLLVMType(instr.X.Type())
@@ -62,7 +62,7 @@ func (b *builder) createChanSend(instr *ssa.Send) {
// actual channel receive operation during goroutine lowering.
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Chan).Elem())
ch := b.getValue(unop.X, getPos(unop))
ch := b.getValue(unop.X)
// Allocate memory to receive into.
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
@@ -140,7 +140,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
var selectStates []llvm.Value
chanSelectStateType := b.getLLVMRuntimeType("chanSelectState")
for _, state := range expr.States {
ch := b.getValue(state.Chan, state.Pos)
ch := b.getValue(state.Chan)
selectState := llvm.ConstNull(chanSelectStateType)
selectState = b.CreateInsertValue(selectState, ch, 0, "")
switch state.Dir {
@@ -156,7 +156,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
case types.SendOnly:
// Store this value in an alloca and put a pointer to this alloca
// in the send state.
sendValue := b.getValue(state.Send, state.Pos)
sendValue := b.getValue(state.Send)
alloca := llvmutil.CreateEntryBlockAlloca(b.Builder, sendValue.Type(), "select.send.value")
b.CreateStore(sendValue, alloca)
ptr := b.CreateBitCast(alloca, b.i8ptrType, "")
@@ -247,7 +247,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
if expr.Index == 0 {
// index
value := b.getValue(expr.Tuple, getPos(expr))
value := b.getValue(expr.Tuple)
index := b.CreateExtractValue(value, expr.Index, "")
if index.Type().IntTypeWidth() < b.intType.IntTypeWidth() {
index = b.CreateSExt(index, b.intType, "")
@@ -255,7 +255,7 @@ func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
return index
} else if expr.Index == 1 {
// comma-ok
value := b.getValue(expr.Tuple, getPos(expr))
value := b.getValue(expr.Tuple)
return b.CreateExtractValue(value, expr.Index, "")
} else {
// Select statements are (index, ok, ...) where ... is a number of
+98 -233
View File
@@ -47,7 +47,6 @@ type Config struct {
CodeModel string
RelocationModel string
SizeLevel int
TinyGoVersion string // for llvm.ident
// Various compiler options that determine how code is generated.
Scheduler string
@@ -71,7 +70,6 @@ type compilerContext struct {
difiles map[string]llvm.Metadata
ditypes map[types.Type]llvm.Metadata
llvmTypes typeutil.Map
interfaceTypes typeutil.Map
machine llvm.TargetMachine
targetData llvm.TargetData
intType llvm.Type
@@ -82,7 +80,6 @@ type compilerContext struct {
uintptrType llvm.Type
program *ssa.Program
diagnostics []error
functionInfos map[*ssa.Function]functionInfo
astComments map[string]*ast.CommentGroup
embedGlobals map[string][]*loader.EmbedFile
pkg *types.Package
@@ -94,14 +91,13 @@ type compilerContext struct {
// importantly with a newly created LLVM context and module.
func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *Config, dumpSSA bool) *compilerContext {
c := &compilerContext{
Config: config,
DumpSSA: dumpSSA,
difiles: make(map[string]llvm.Metadata),
ditypes: make(map[types.Type]llvm.Metadata),
machine: machine,
targetData: machine.CreateTargetData(),
functionInfos: map[*ssa.Function]functionInfo{},
astComments: map[string]*ast.CommentGroup{},
Config: config,
DumpSSA: dumpSSA,
difiles: make(map[string]llvm.Metadata),
ditypes: make(map[types.Type]llvm.Metadata),
machine: machine,
targetData: machine.CreateTargetData(),
astComments: map[string]*ast.CommentGroup{},
}
c.ctx = llvm.NewContext()
@@ -169,8 +165,6 @@ type builder struct {
deferExprFuncs map[ssa.Value]int
selectRecvBuf map[*ssa.Select]llvm.Value
deferBuiltinFuncs map[ssa.Value]deferBuiltin
runDefersBlock []llvm.BasicBlock
afterDefersBlock []llvm.BasicBlock
}
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
@@ -327,14 +321,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(),
}),
)
if c.TinyGoVersion != "" {
// It is necessary to set llvm.ident, otherwise debugging on MacOS
// won't work.
c.mod.AddNamedMetadataOperand("llvm.ident",
c.ctx.MDNode(([]llvm.Metadata{
c.ctx.MDString("TinyGo version " + c.TinyGoVersion),
})))
}
c.dibuilder.Finalize()
c.dibuilder.Destroy()
}
@@ -574,19 +560,10 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
case *types.Map:
return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type()))
case *types.Named:
// Placeholder metadata node, to be replaced afterwards.
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
Tag: dwarf.TagTypedef,
SizeInBits: sizeInBytes * 8,
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
})
c.ditypes[typ] = temporaryMDNode
md := c.dibuilder.CreateTypedef(llvm.DITypedef{
return c.dibuilder.CreateTypedef(llvm.DITypedef{
Type: c.getDIType(typ.Underlying()),
Name: typ.String(),
})
temporaryMDNode.ReplaceAllUsesWith(md)
return md
case *types.Pointer:
return c.dibuilder.CreatePointerType(llvm.DIPointerType{
Pointee: c.getDIType(typ.Elem()),
@@ -648,6 +625,13 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
},
})
case *types.Struct:
// Placeholder metadata node, to be replaced afterwards.
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
Tag: dwarf.TagStructType,
SizeInBits: sizeInBytes * 8,
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
})
c.ditypes[typ] = temporaryMDNode
elements := make([]llvm.Metadata, typ.NumFields())
for i := range elements {
field := typ.Field(i)
@@ -666,6 +650,7 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
Elements: elements,
})
temporaryMDNode.ReplaceAllUsesWith(md)
return md
case *types.TypeParam:
return c.getDIType(typ.Underlying())
@@ -849,11 +834,6 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
b.defineMathOp()
continue
}
if ok := b.defineMathBitsIntrinsic(); ok {
// Like a math intrinsic, the body of this function was replaced
// with a LLVM intrinsic.
continue
}
if member.Blocks == nil {
// Try to define this as an intrinsic function.
b.defineIntrinsicFunction()
@@ -880,14 +860,14 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
if fn == nil {
continue // probably a generic method
}
if fn.Blocks == nil {
continue // external function
}
if member.Type().String() != member.String() {
// This is a member on a type alias. Do not build such a
// function.
continue
}
if fn.Blocks == nil {
continue // external function
}
if fn.Synthetic != "" && fn.Synthetic != "package initializer" {
// This function is a kind of wrapper function (created by
// the ssa package, not appearing in the source code) that
@@ -981,19 +961,6 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
global.SetInitializer(sliceObj)
global.SetVisibility(llvm.HiddenVisibility)
if c.Debug {
// Add debug info to the slice backing array.
position := c.program.Fset.Position(member.Pos())
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
File: c.getDIFile(position.Filename),
Line: position.Line,
Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(file.Data)))),
LocalToUnit: true,
Expr: c.dibuilder.CreateExpression(nil),
})
bufferGlobal.AddMetadata(0, diglobal)
}
case *types.Struct:
// Assume this is an embed.FS struct:
// https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/embed/embed.go;l=148
@@ -1034,12 +1001,11 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
})
// Make the backing array for the []files slice. This is a LLVM global.
embedFileStructType := typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem()
llvmEmbedFileStructType := c.getLLVMType(embedFileStructType)
embedFileStructType := c.getLLVMType(typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem())
var fileStructs []llvm.Value
for _, file := range allFiles {
fileStruct := llvm.ConstNull(llvmEmbedFileStructType)
name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]), getPos(member))
fileStruct := llvm.ConstNull(embedFileStructType)
name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]))
fileStruct = c.builder.CreateInsertValue(fileStruct, name, 0, "") // "name" field
if file.Hash != "" {
data := c.getEmbedFileString(file)
@@ -1047,25 +1013,13 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
}
fileStructs = append(fileStructs, fileStruct)
}
sliceDataInitializer := llvm.ConstArray(llvmEmbedFileStructType, fileStructs)
sliceDataInitializer := llvm.ConstArray(embedFileStructType, fileStructs)
sliceDataGlobal := llvm.AddGlobal(c.mod, sliceDataInitializer.Type(), c.pkg.Path()+"$embedfsfiles")
sliceDataGlobal.SetInitializer(sliceDataInitializer)
sliceDataGlobal.SetLinkage(llvm.InternalLinkage)
sliceDataGlobal.SetGlobalConstant(true)
sliceDataGlobal.SetUnnamedAddr(true)
sliceDataGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceDataInitializer.Type()))
if c.Debug {
// Add debug information for code size attribution (among others).
position := c.program.Fset.Position(member.Pos())
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
File: c.getDIFile(position.Filename),
Line: position.Line,
Type: c.getDIType(types.NewArray(embedFileStructType, int64(len(allFiles)))),
LocalToUnit: true,
Expr: c.dibuilder.CreateExpression(nil),
})
sliceDataGlobal.AddMetadata(0, diglobal)
}
// Create the slice object itself.
// Because embed.FS refers to it as *[]embed.file instead of a plain
@@ -1082,17 +1036,6 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
sliceGlobal.SetGlobalConstant(true)
sliceGlobal.SetUnnamedAddr(true)
sliceGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceInitializer.Type()))
if c.Debug {
position := c.program.Fset.Position(member.Pos())
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
File: c.getDIFile(position.Filename),
Line: position.Line,
Type: c.getDIType(types.NewSlice(embedFileStructType)),
LocalToUnit: true,
Expr: c.dibuilder.CreateExpression(nil),
})
sliceGlobal.AddMetadata(0, diglobal)
}
// Define the embed.FS struct. It has only one field: the files (as a
// *[]embed.file).
@@ -1332,7 +1275,7 @@ func (b *builder) createFunction() {
}
dbgVar := b.getLocalVariable(variable)
pos := b.program.Fset.Position(instr.Pos())
b.dibuilder.InsertValueAtEnd(b.getValue(instr.X, getPos(instr)), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
b.dibuilder.InsertValueAtEnd(b.getValue(instr.X), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
Line: uint(pos.Line),
Col: uint(pos.Column),
Scope: b.difunc,
@@ -1353,15 +1296,6 @@ func (b *builder) createFunction() {
}
}
// The rundefers instruction needs to be created after all defer
// instructions have been created. Otherwise it won't handle all defer
// cases.
for i, bb := range b.runDefersBlock {
b.SetInsertPointAtEnd(bb)
b.createRunDefers()
b.CreateBr(b.afterDefersBlock[i])
}
if b.hasDeferFrame() {
// Create the landing pad block, where execution continues after a
// panic.
@@ -1372,7 +1306,7 @@ func (b *builder) createFunction() {
for _, phi := range b.phis {
block := phi.ssa.Block()
for i, edge := range phi.ssa.Edges {
llvmVal := b.getValue(edge, getPos(phi.ssa))
llvmVal := b.getValue(edge)
llvmBlock := b.blockExits[block.Preds[i]]
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
}
@@ -1480,7 +1414,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
// Start a new goroutine.
b.createGo(instr)
case *ssa.If:
cond := b.getValue(instr.Cond, getPos(instr))
cond := b.getValue(instr.Cond)
block := instr.Block()
blockThen := b.blockEntries[block.Succs[0]]
blockElse := b.blockEntries[block.Succs[1]]
@@ -1489,13 +1423,13 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
blockJump := b.blockEntries[instr.Block().Succs[0]]
b.CreateBr(blockJump)
case *ssa.MapUpdate:
m := b.getValue(instr.Map, getPos(instr))
key := b.getValue(instr.Key, getPos(instr))
value := b.getValue(instr.Value, getPos(instr))
m := b.getValue(instr.Map)
key := b.getValue(instr.Key)
value := b.getValue(instr.Value)
mapType := instr.Map.Type().Underlying().(*types.Map)
b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
case *ssa.Panic:
value := b.getValue(instr.X, getPos(instr))
value := b.getValue(instr.X)
b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
b.CreateUnreachable()
case *ssa.Return:
@@ -1505,30 +1439,23 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
if len(instr.Results) == 0 {
b.CreateRetVoid()
} else if len(instr.Results) == 1 {
b.CreateRet(b.getValue(instr.Results[0], getPos(instr)))
b.CreateRet(b.getValue(instr.Results[0]))
} else {
// Multiple return values. Put them all in a struct.
retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType())
for i, result := range instr.Results {
val := b.getValue(result, getPos(instr))
val := b.getValue(result)
retVal = b.CreateInsertValue(retVal, val, i, "")
}
b.CreateRet(retVal)
}
case *ssa.RunDefers:
// Note where we're going to put the rundefers block
run := b.insertBasicBlock("rundefers.block")
b.CreateBr(run)
b.runDefersBlock = append(b.runDefersBlock, run)
after := b.insertBasicBlock("rundefers.after")
b.SetInsertPointAtEnd(after)
b.afterDefersBlock = append(b.afterDefersBlock, after)
b.createRunDefers()
case *ssa.Send:
b.createChanSend(instr)
case *ssa.Store:
llvmAddr := b.getValue(instr.Addr, getPos(instr))
llvmVal := b.getValue(instr.Val, getPos(instr))
llvmAddr := b.getValue(instr.Addr)
llvmVal := b.getValue(instr.Val)
b.createNilCheck(instr.Addr, llvmAddr, "store")
if b.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
// nothing to store
@@ -1600,45 +1527,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
cplx = b.CreateInsertValue(cplx, r, 0, "")
cplx = b.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
case "clear":
value := argValues[0]
switch typ := argTypes[0].Underlying().(type) {
case *types.Slice:
elementType := b.getLLVMType(typ.Elem())
elementSize := b.targetData.TypeAllocSize(elementType)
elementAlign := b.targetData.ABITypeAlignment(elementType)
// The pointer to the data to be cleared.
llvmBuf := b.CreateExtractValue(value, 0, "buf")
if llvmBuf.Type() != b.i8ptrType { // compatibility with LLVM 14
llvmBuf = b.CreateBitCast(llvmBuf, b.i8ptrType, "")
}
// The length (in bytes) to be cleared.
llvmLen := b.CreateExtractValue(value, 1, "len")
llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "")
// Do the clear operation using the LLVM memset builtin.
// This is also correct for nil slices: in those cases, len will be
// 0 which means the memset call is a no-op (according to the LLVM
// LangRef).
memset := b.getMemsetFunc()
call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{
llvmBuf, // dest
llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val
llvmLen, // len
llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile
}, "")
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
return llvm.Value{}, nil
case *types.Map:
m := argValues[0]
b.createMapClear(m)
return llvm.Value{}, nil
default:
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
}
case "copy":
dst := argValues[0]
src := argValues[1]
@@ -1676,24 +1564,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
}
return llvmLen, nil
case "min", "max":
// min and max builtins, added in Go 1.21.
// We can simply reuse the existing binop comparison code, which has all
// the edge cases figured out already.
tok := token.LSS
if callName == "max" {
tok = token.GTR
}
result := argValues[0]
typ := argTypes[0]
for _, arg := range argValues[1:] {
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
if err != nil {
return result, err
}
result = b.CreateSelect(cmp, result, arg, "")
}
return result, nil
case "print", "println":
for i, value := range argValues {
if i >= 1 && callName == "println" {
@@ -1844,7 +1714,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) {
var params []llvm.Value
for _, param := range instr.Args {
params = append(params, b.getValue(param, getPos(instr)))
params = append(params, b.getValue(param))
}
// Try to call the function directly for trivially static calls.
@@ -1861,9 +1731,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
return b.createInlineAsmFull(instr)
case strings.HasPrefix(name, "device/arm.SVCall"):
return b.emitSVCall(instr.Args, getPos(instr))
return b.emitSVCall(instr.Args)
case strings.HasPrefix(name, "device/arm64.SVCall"):
return b.emitSV64Call(instr.Args, getPos(instr))
return b.emitSV64Call(instr.Args)
case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr)
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
@@ -1900,7 +1770,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
case *ssa.MakeClosure:
// A call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
funcValue := b.getValue(value, getPos(value))
funcValue := b.getValue(value)
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
@@ -1915,7 +1785,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.createBuiltin(argTypes, params, call.Name(), instr.Pos())
} else if instr.IsInvoke() {
// Interface method call (aka invoke call).
itf := b.getValue(instr.Value, getPos(instr)) // interface value (runtime._interface)
itf := b.getValue(instr.Value) // interface value (runtime._interface)
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
value := b.CreateExtractValue(itf, 1, "invoke.func.value") // receiver
// Prefix the params with receiver value and suffix with typecode.
@@ -1926,7 +1796,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
context = llvm.Undef(b.i8ptrType)
} else {
// Function pointer.
value := b.getValue(instr.Value, getPos(instr))
value := b.getValue(instr.Value)
// This is a func value, which cannot be called directly. We have to
// extract the function pointer and context first from the func value.
calleeType, callee, context = b.decodeFuncValue(value, instr.Value.Type().Underlying().(*types.Signature))
@@ -1944,18 +1814,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
// getValue returns the LLVM value of a constant, function value, global, or
// already processed SSA expression.
func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
func (b *builder) getValue(expr ssa.Value) llvm.Value {
switch expr := expr.(type) {
case *ssa.Const:
if pos == token.NoPos {
// If the position isn't known, at least try to find in which file
// it is defined.
file := b.program.Fset.File(b.fn.Pos())
if file != nil {
pos = file.Pos(0)
}
}
return b.createConst(expr, pos)
return b.createConst(expr)
case *ssa.Function:
if b.getFunctionInfo(expr).exported {
b.addError(expr.Pos(), "cannot use an exported function as value: "+expr.String())
@@ -2040,8 +1902,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
return buf, nil
}
case *ssa.BinOp:
x := b.getValue(expr.X, getPos(expr))
y := b.getValue(expr.Y, getPos(expr))
x := b.getValue(expr.X)
y := b.getValue(expr.Y)
return b.createBinOp(expr.Op, expr.X.Type(), expr.Y.Type(), x, y, expr.Pos())
case *ssa.Call:
return b.createFunctionCall(expr.Common())
@@ -2052,12 +1914,12 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
// This is different from how the official Go compiler works, because of
// heap allocation and because it's easier to implement, see:
// https://research.swtch.com/interfaces
return b.getValue(expr.X, getPos(expr)), nil
return b.getValue(expr.X), nil
case *ssa.ChangeType:
// This instruction changes the type, but the underlying value remains
// the same. This is often a no-op, but sometimes we have to change the
// LLVM type as well.
x := b.getValue(expr.X, getPos(expr))
x := b.getValue(expr.X)
llvmType := b.getLLVMType(expr.Type())
if x.Type() == llvmType {
// Different Go type but same LLVM type (for example, named int).
@@ -2086,20 +1948,20 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
case *ssa.Const:
panic("const is not an expression")
case *ssa.Convert:
x := b.getValue(expr.X, getPos(expr))
x := b.getValue(expr.X)
return b.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
case *ssa.Extract:
if _, ok := expr.Tuple.(*ssa.Select); ok {
return b.getChanSelectResult(expr), nil
}
value := b.getValue(expr.Tuple, getPos(expr))
value := b.getValue(expr.Tuple)
return b.CreateExtractValue(value, expr.Index, ""), nil
case *ssa.Field:
value := b.getValue(expr.X, getPos(expr))
value := b.getValue(expr.X)
result := b.CreateExtractValue(value, expr.Field, "")
return result, nil
case *ssa.FieldAddr:
val := b.getValue(expr.X, getPos(expr))
val := b.getValue(expr.X)
// Check for nil pointer before calculating the address, from the spec:
// > For an operand x of type T, the address operation &x generates a
// > pointer of type *T to x. [...] If the evaluation of x would cause a
@@ -2117,8 +1979,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
case *ssa.Global:
panic("global is not an expression")
case *ssa.Index:
collection := b.getValue(expr.X, getPos(expr))
index := b.getValue(expr.Index, getPos(expr))
collection := b.getValue(expr.X)
index := b.getValue(expr.Index)
switch xType := expr.X.Type().Underlying().(type) {
case *types.Basic: // extract byte from string
@@ -2167,8 +2029,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
panic("unknown *ssa.Index type")
}
case *ssa.IndexAddr:
val := b.getValue(expr.X, getPos(expr))
index := b.getValue(expr.Index, getPos(expr))
val := b.getValue(expr.X)
index := b.getValue(expr.Index)
// Get buffer pointer and length
var bufptr, buflen llvm.Value
@@ -2219,8 +2081,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
panic("unreachable")
}
case *ssa.Lookup: // map lookup
value := b.getValue(expr.X, getPos(expr))
index := b.getValue(expr.Index, getPos(expr))
value := b.getValue(expr.X)
index := b.getValue(expr.Index)
valueType := expr.Type()
if expr.CommaOk {
valueType = valueType.(*types.Tuple).At(0).Type()
@@ -2231,13 +2093,13 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
case *ssa.MakeClosure:
return b.parseMakeClosure(expr)
case *ssa.MakeInterface:
val := b.getValue(expr.X, getPos(expr))
val := b.getValue(expr.X)
return b.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil
case *ssa.MakeMap:
return b.createMakeMap(expr)
case *ssa.MakeSlice:
sliceLen := b.getValue(expr.Len, getPos(expr))
sliceCap := b.getValue(expr.Cap, getPos(expr))
sliceLen := b.getValue(expr.Len)
sliceCap := b.getValue(expr.Cap)
sliceType := expr.Type().Underlying().(*types.Slice)
llvmElemType := b.getLLVMType(sliceType.Elem())
elemSize := b.targetData.TypeAllocSize(llvmElemType)
@@ -2289,8 +2151,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
return slice, nil
case *ssa.Next:
rangeVal := expr.Iter.(*ssa.Range).X
llvmRangeVal := b.getValue(rangeVal, getPos(expr))
it := b.getValue(expr.Iter, getPos(expr))
llvmRangeVal := b.getValue(rangeVal)
it := b.getValue(expr.Iter)
if expr.IsString {
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
} else { // map
@@ -2316,14 +2178,14 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
case *ssa.Select:
return b.createSelect(expr), nil
case *ssa.Slice:
value := b.getValue(expr.X, getPos(expr))
value := b.getValue(expr.X)
var lowType, highType, maxType *types.Basic
var low, high, max llvm.Value
if expr.Low != nil {
lowType = expr.Low.Type().Underlying().(*types.Basic)
low = b.getValue(expr.Low, getPos(expr))
low = b.getValue(expr.Low)
low = b.extendInteger(low, lowType, b.uintptrType)
} else {
lowType = types.Typ[types.Uintptr]
@@ -2332,7 +2194,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
if expr.High != nil {
highType = expr.High.Type().Underlying().(*types.Basic)
high = b.getValue(expr.High, getPos(expr))
high = b.getValue(expr.High)
high = b.extendInteger(high, highType, b.uintptrType)
} else {
highType = types.Typ[types.Uintptr]
@@ -2340,7 +2202,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
if expr.Max != nil {
maxType = expr.Max.Type().Underlying().(*types.Basic)
max = b.getValue(expr.Max, getPos(expr))
max = b.getValue(expr.Max)
max = b.extendInteger(max, maxType, b.uintptrType)
} else {
maxType = types.Typ[types.Uintptr]
@@ -2473,7 +2335,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
// Conversion from a slice to an array pointer, as the name clearly
// says. This requires a runtime check to make sure the slice is at
// least as big as the array.
slice := b.getValue(expr.X, getPos(expr))
slice := b.getValue(expr.X)
sliceLen := b.CreateExtractValue(slice, 1, "")
arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()
b.createSliceToArrayPointerCheck(sliceLen, arrayLen)
@@ -2906,7 +2768,7 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
}
// createConst creates a LLVM constant value from a Go constant.
func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value {
func (c *compilerContext) createConst(expr *ssa.Const) llvm.Value {
switch typ := expr.Type().Underlying().(type) {
case *types.Basic:
llvmType := c.getLLVMType(typ)
@@ -2929,18 +2791,6 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
global.SetGlobalConstant(true)
global.SetUnnamedAddr(true)
global.SetAlignment(1)
if c.Debug {
// Unfortunately, expr.Pos() is always token.NoPos.
position := c.program.Fset.Position(pos)
diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
File: c.getDIFile(position.Filename),
Line: position.Line,
Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(str)))),
LocalToUnit: true,
Expr: c.dibuilder.CreateExpression(nil),
})
global.AddMetadata(0, diglobal)
}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero})
} else {
@@ -2964,15 +2814,15 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
n, _ := constant.Float64Val(expr.Value)
return llvm.ConstFloat(llvmType, n)
} else if typ.Kind() == types.Complex64 {
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]), pos)
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]), pos)
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx
} else if typ.Kind() == types.Complex128 {
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]), pos)
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]), pos)
r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
@@ -3005,11 +2855,6 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
panic("expected nil pointer constant")
}
return llvm.ConstPointerNull(c.getLLVMType(typ))
case *types.Array:
if expr.Value != nil {
panic("expected nil array constant")
}
return llvm.ConstNull(c.getLLVMType(expr.Type()))
case *types.Slice:
if expr.Value != nil {
panic("expected nil slice constant")
@@ -3023,11 +2868,6 @@ func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value
llvmLen, // cap
}, false)
return slice
case *types.Struct:
if expr.Value != nil {
panic("expected nil struct constant")
}
return llvm.ConstNull(c.getLLVMType(expr.Type()))
case *types.Map:
if !expr.IsNil() {
// I believe this is not allowed by the Go spec.
@@ -3051,6 +2891,31 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
if isPtrFrom && !isPtrTo {
return b.CreatePtrToInt(value, llvmTypeTo, ""), nil
} else if !isPtrFrom && isPtrTo {
if !value.IsABinaryOperator().IsNil() && value.InstructionOpcode() == llvm.Add {
// This is probably a pattern like the following:
// unsafe.Pointer(uintptr(ptr) + index)
// Used in functions like memmove etc. for lack of pointer
// arithmetic. Convert it to real pointer arithmatic here.
ptr := value.Operand(0)
index := value.Operand(1)
if !index.IsAPtrToIntInst().IsNil() {
// Swap if necessary, if ptr and index are reversed.
ptr, index = index, ptr
}
if !ptr.IsAPtrToIntInst().IsNil() {
origptr := ptr.Operand(0)
if origptr.Type() == b.i8ptrType {
// This pointer can be calculated from the original
// ptrtoint instruction with a GEP. The leftover inttoptr
// instruction is trivial to optimize away.
// Making it an in bounds GEP even though it's easy to
// create a GEP that is not in bounds. However, we're
// talking about unsafe code here so the programmer has to
// be careful anyway.
return b.CreateInBoundsGEP(b.ctx.Int8Type(), origptr, []llvm.Value{index}, ""), nil
}
}
}
return b.CreateIntToPtr(value, llvmTypeTo, ""), nil
}
@@ -3253,7 +3118,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
// which can all be directly lowered to IR. However, there is also the channel
// receive operator which is handled in the runtime directly.
func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
x := b.getValue(unop.X, getPos(unop))
x := b.getValue(unop.X)
switch unop.Op {
case token.NOT: // !x
return b.CreateNot(x, ""), nil
+44 -90
View File
@@ -29,7 +29,7 @@ func TestCompiler(t *testing.T) {
t.Parallel()
// Determine Go minor version (e.g. 16 in go1.16.3).
_, goMinor, err := goenv.GetGorootVersion()
_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
if err != nil {
t.Fatal("could not read Go version:", err)
}
@@ -49,14 +49,10 @@ func TestCompiler(t *testing.T) {
{"goroutine.go", "cortex-m-qemu", "tasks"},
{"channel.go", "", ""},
{"gc.go", "", ""},
{"zeromap.go", "", ""},
}
if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""})
}
if goMinor >= 21 {
tests = append(tests, testCase{"go1.21.go", "", ""})
}
for _, tc := range tests {
name := tc.file
@@ -73,11 +69,52 @@ func TestCompiler(t *testing.T) {
options := &compileopts.Options{
Target: targetString,
}
target, err := compileopts.LoadTarget(options)
if err != nil {
t.Fatal("failed to load target:", err)
}
if tc.scheduler != "" {
options.Scheduler = tc.scheduler
}
config := &compileopts.Config{
Options: options,
Target: target,
}
compilerConfig := &Config{
Triple: config.Triple(),
Features: config.Features(),
ABI: config.ABI(),
GOOS: config.GOOS(),
GOARCH: config.GOARCH(),
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
t.Fatal("failed to create target machine:", err)
}
defer machine.Dispose()
mod, errs := testCompilePackage(t, options, tc.file)
// Load entire program AST into memory.
lprogram, err := loader.Load(config, "./testdata/"+tc.file, config.ClangHeaders, types.Config{
Sizes: Sizes(machine),
})
if err != nil {
t.Fatal("failed to create target machine:", err)
}
err = lprogram.Parse()
if err != nil {
t.Fatalf("could not parse test case %s: %s", tc.file, err)
}
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
mod, errs := CompilePackage(tc.file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
if errs != nil {
for _, err := range errs {
t.Error(err)
@@ -85,7 +122,7 @@ func TestCompiler(t *testing.T) {
return
}
err := llvm.VerifyModule(mod, llvm.PrintMessageAction)
err = llvm.VerifyModule(mod, llvm.PrintMessageAction)
if err != nil {
t.Error(err)
}
@@ -178,86 +215,3 @@ func filterIrrelevantIRLines(lines []string) []string {
}
return out
}
func TestCompilerErrors(t *testing.T) {
t.Parallel()
// Read expected errors from the test file.
var expectedErrors []string
errorsFile, err := os.ReadFile("testdata/errors.go")
if err != nil {
t.Error(err)
}
errorsFileString := strings.ReplaceAll(string(errorsFile), "\r\n", "\n")
for _, line := range strings.Split(errorsFileString, "\n") {
if strings.HasPrefix(line, "// ERROR: ") {
expectedErrors = append(expectedErrors, strings.TrimPrefix(line, "// ERROR: "))
}
}
// Compile the Go file with errors.
options := &compileopts.Options{
Target: "wasm",
}
_, errs := testCompilePackage(t, options, "errors.go")
// Check whether the actual errors match the expected errors.
expectedErrorsIdx := 0
for _, err := range errs {
err := err.(types.Error)
position := err.Fset.Position(err.Pos)
position.Filename = "errors.go" // don't use a full path
if expectedErrorsIdx >= len(expectedErrors) || expectedErrors[expectedErrorsIdx] != err.Msg {
t.Errorf("unexpected compiler error: %s: %s", position.String(), err.Msg)
continue
}
expectedErrorsIdx++
}
}
// Build a package given a number of compiler options and a file.
func testCompilePackage(t *testing.T, options *compileopts.Options, file string) (llvm.Module, []error) {
target, err := compileopts.LoadTarget(options)
if err != nil {
t.Fatal("failed to load target:", err)
}
config := &compileopts.Config{
Options: options,
Target: target,
}
compilerConfig := &Config{
Triple: config.Triple(),
Features: config.Features(),
ABI: config.ABI(),
GOOS: config.GOOS(),
GOARCH: config.GOARCH(),
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
t.Fatal("failed to create target machine:", err)
}
defer machine.Dispose()
// Load entire program AST into memory.
lprogram, err := loader.Load(config, "./testdata/"+file, config.ClangHeaders, types.Config{
Sizes: Sizes(machine),
})
if err != nil {
t.Fatal("failed to create target machine:", err)
}
err = lprogram.Parse()
if err != nil {
t.Fatalf("could not parse test case %s: %s", file, err)
}
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
return CompilePackage(file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
}
+10 -10
View File
@@ -31,7 +31,7 @@ func (b *builder) supportsRecover() bool {
// proposal of WebAssembly:
// https://github.com/WebAssembly/exception-handling
return false
case "riscv64", "xtensa":
case "riscv64", "xtensa", "mips":
// TODO: add support for these architectures
return false
default:
@@ -267,13 +267,13 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// Collect all values to be put in the struct (starting with
// runtime._defer fields, followed by the call parameters).
itf := b.getValue(instr.Call.Value, getPos(instr)) // interface
itf := b.getValue(instr.Call.Value) // interface
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
values = []llvm.Value{callback, next, typecode, receiverValue}
valueTypes = append(valueTypes, b.i8ptrType, b.i8ptrType)
for _, arg := range instr.Call.Args {
val := b.getValue(arg, getPos(instr))
val := b.getValue(arg)
values = append(values, val)
valueTypes = append(valueTypes, val.Type())
}
@@ -290,7 +290,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// runtime._defer fields).
values = []llvm.Value{callback, next}
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param, getPos(instr))
llvmParam := b.getValue(param)
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
@@ -302,7 +302,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// pointer.
// TODO: ignore this closure entirely and put pointers to the free
// variables directly in the defer struct, avoiding a memory allocation.
closure := b.getValue(instr.Call.Value, getPos(instr))
closure := b.getValue(instr.Call.Value)
context := b.CreateExtractValue(closure, 0, "")
// Get the callback number.
@@ -318,7 +318,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// context pointer).
values = []llvm.Value{callback, next}
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param, getPos(instr))
llvmParam := b.getValue(param)
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
@@ -330,7 +330,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
var argValues []llvm.Value
for _, arg := range instr.Call.Args {
argTypes = append(argTypes, arg.Type())
argValues = append(argValues, b.getValue(arg, getPos(instr)))
argValues = append(argValues, b.getValue(arg))
}
if _, ok := b.deferBuiltinFuncs[instr.Call.Value]; !ok {
@@ -353,7 +353,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
}
} else {
funcValue := b.getValue(instr.Call.Value, getPos(instr))
funcValue := b.getValue(instr.Call.Value)
if _, ok := b.deferExprFuncs[instr.Call.Value]; !ok {
b.deferExprFuncs[instr.Call.Value] = len(b.allDeferFuncs)
@@ -368,7 +368,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
values = []llvm.Value{callback, next, funcValue}
valueTypes = append(valueTypes, funcValue.Type())
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param, getPos(instr))
llvmParam := b.getValue(param)
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
@@ -544,7 +544,7 @@ func (b *builder) createRunDefers() {
forwardParams = append(forwardParams, forwardParam)
}
// Plain TinyGo functions add some extra parameters to implement async functionality and function receivers.
// Plain TinyGo functions add some extra parameters to implement async functionality and function recievers.
// These parameters should not be supplied when calling into an external C/ASM function.
if !b.getFunctionInfo(callback).exported {
// Add the context parameter. We know it is ignored by the receiving
+2 -3
View File
@@ -32,8 +32,7 @@ func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context
// global reference is not real, it is only used during func lowering to assign
// signature types to functions and will then be removed.
func (c *compilerContext) getFuncSignatureID(sig *types.Signature) llvm.Value {
s, _ := getTypeCodeName(sig)
sigGlobalName := "reflect/types.funcid:" + s
sigGlobalName := "reflect/types.funcid:" + getTypeCodeName(sig)
sigGlobal := c.mod.NamedGlobal(sigGlobalName)
if sigGlobal.IsNil() {
sigGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), sigGlobalName)
@@ -135,7 +134,7 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
boundVars := make([]llvm.Value, len(expr.Bindings))
for i, binding := range expr.Bindings {
// The context stores the bound variables.
llvmBoundVar := b.getValue(binding, getPos(expr))
llvmBoundVar := b.getValue(binding)
boundVars[i] = llvmBoundVar
}
+5 -5
View File
@@ -16,7 +16,7 @@ func (b *builder) createGo(instr *ssa.Go) {
// 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)))
params = append(params, b.getValue(param))
}
var prefix string
@@ -33,7 +33,7 @@ func (b *builder) createGo(instr *ssa.Go) {
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))
funcValue := b.getValue(value)
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
@@ -70,13 +70,13 @@ func (b *builder) createGo(instr *ssa.Go) {
var argValues []llvm.Value
for _, arg := range instr.Call.Args {
argTypes = append(argTypes, arg.Type())
argValues = append(argValues, b.getValue(arg, getPos(instr)))
argValues = append(argValues, b.getValue(arg))
}
b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos())
return
} else if instr.Call.IsInvoke() {
// This is a method call on an interface value.
itf := b.getValue(instr.Call.Value, getPos(instr))
itf := b.getValue(instr.Call.Value)
itfTypeCode := b.CreateExtractValue(itf, 0, "")
itfValue := b.CreateExtractValue(itf, 1, "")
funcPtr = b.getInvokeFunction(&instr.Call)
@@ -90,7 +90,7 @@ func (b *builder) createGo(instr *ssa.Go) {
// * The function context, for closures.
// * The function pointer (for tasks).
var context llvm.Value
funcPtrType, funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)), instr.Call.Value.Type().Underlying().(*types.Signature))
funcPtrType, funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
params = append(params, context, funcPtr)
hasContext = true
prefix = b.fn.RelString(nil)
+8 -9
View File
@@ -5,7 +5,6 @@ package compiler
import (
"fmt"
"go/constant"
"go/token"
"regexp"
"strconv"
"strings"
@@ -56,7 +55,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
return llvm.Value{}, b.makeError(instr.Pos(), "register value map must be created in the same basic block")
}
key := constant.StringVal(r.Key.(*ssa.Const).Value)
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X, getPos(instr))
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X)
case *ssa.Call:
if r.Common() == instr {
break
@@ -141,7 +140,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
//
// The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly.
func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
llvmArgs := []llvm.Value{}
argTypes := []llvm.Type{}
@@ -154,7 +153,7 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error
} else {
constraints += ",{r" + strconv.Itoa(i) + "}"
}
llvmValue := b.getValue(arg, pos)
llvmValue := b.getValue(arg)
llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -179,7 +178,7 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error
// The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly.
// Same as emitSVCall but for AArch64
func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
llvmArgs := []llvm.Value{}
argTypes := []llvm.Type{}
@@ -192,7 +191,7 @@ func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, err
} else {
constraints += ",{x" + strconv.Itoa(i) + "}"
}
llvmValue := b.getValue(arg, pos)
llvmValue := b.getValue(arg)
llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -232,19 +231,19 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrw %d, $0", csr)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "SetBits":
// Note: it may be possible to optimize this to csrrsi in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "ClearBits":
// Note: it may be possible to optimize this to csrrci in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
}
+39 -250
View File
@@ -6,7 +6,6 @@ package compiler
// interface-lowering.go for more details.
import (
"encoding/binary"
"fmt"
"go/token"
"go/types"
@@ -58,15 +57,6 @@ const (
structFieldFlagAnonymous = 1 << iota
structFieldFlagHasTag
structFieldFlagIsExported
structFieldFlagIsEmbedded
)
type reflectChanDir int
const (
refRecvDir reflectChanDir = 1 << iota // <-chan
refSendDir // chan<-
refBothDir = refRecvDir | refSendDir // chan
)
// createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction.
@@ -93,30 +83,6 @@ func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type)
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
}
func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
pkgpathName := "reflect/types.type.pkgpath.empty"
if pkgpath != "" {
pkgpathName = "reflect/types.type.pkgpath:" + pkgpath
}
pkgpathGlobal := c.mod.NamedGlobal(pkgpathName)
if pkgpathGlobal.IsNil() {
pkgpathInitializer := c.ctx.ConstString(pkgpath+"\x00", false)
pkgpathGlobal = llvm.AddGlobal(c.mod, pkgpathInitializer.Type(), pkgpathName)
pkgpathGlobal.SetInitializer(pkgpathInitializer)
pkgpathGlobal.SetAlignment(1)
pkgpathGlobal.SetUnnamedAddr(true)
pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
pkgpathGlobal.SetGlobalConstant(true)
}
pkgPathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
})
return pkgPathPtr
}
// getTypeCode returns a reference to a type code.
// A type code is a pointer to a constant global that describes the type.
// This function returns a pointer to the 'kind' field (which might not be the
@@ -127,48 +93,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
if _, ok := typ.Underlying().(*types.Interface); ok {
hasMethodSet = false
}
var numMethods int
if hasMethodSet {
for i := 0; i < ms.Len(); i++ {
if ms.At(i).Obj().Exported() {
numMethods++
}
}
}
// Short-circuit all the global pointer logic here for pointers to pointers.
if typ, ok := typ.(*types.Pointer); ok {
if _, ok := typ.Elem().(*types.Pointer); ok {
// For a pointer to a pointer, we just increase the pointer by 1
ptr := c.getTypeCode(typ.Elem())
// if the type is already *****T or higher, we can't make it.
if typstr := typ.String(); strings.HasPrefix(typstr, "*****") {
c.addError(token.NoPos, fmt.Sprintf("too many levels of pointers for typecode: %s", typstr))
}
return llvm.ConstGEP(c.ctx.Int8Type(), ptr, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 1, false),
})
}
}
typeCodeName, isLocal := getTypeCodeName(typ)
globalName := "reflect/types.type:" + typeCodeName
var global llvm.Value
if isLocal {
// This type is a named type inside a function, like this:
//
// func foo() any {
// type named int
// return named(0)
// }
if obj := c.interfaceTypes.At(typ); obj != nil {
global = obj.(llvm.Value)
}
} else {
// Regular type (named or otherwise).
global = c.mod.NamedGlobal(globalName)
}
globalName := "reflect/types.type:" + getTypeCodeName(typ)
global := c.mod.NamedGlobal(globalName)
if global.IsNil() {
var typeFields []llvm.Value
// Define the type fields. These must match the structs in
@@ -183,57 +109,33 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
)
case *types.Named:
name := typ.Obj().Name()
var pkgname string
if pkg := typ.Obj().Pkg(); pkg != nil {
pkgname = pkg.Name()
}
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
)
case *types.Chan:
case *types.Chan, *types.Slice:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), // reuse for select chan direction
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
)
case *types.Slice:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
)
case *types.Pointer:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
)
case *types.Array:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
types.NewVar(token.NoPos, nil, "sliceOf", types.Typ[types.UnsafePointer]),
)
case *types.Map:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "keyType", types.Typ[types.UnsafePointer]),
)
case *types.Struct:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uint32]),
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
)
case *types.Interface:
@@ -260,106 +162,47 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
}
globalType := types.NewStruct(typeFieldTypes, nil)
global = llvm.AddGlobal(c.mod, c.getLLVMType(globalType), globalName)
if isLocal {
c.interfaceTypes.Set(typ, global)
}
metabyte := getTypeKind(typ)
// Precompute these so we don't have to calculate them at runtime.
if types.Comparable(typ) {
metabyte |= 1 << 6
}
if hashmapIsBinaryKey(typ) {
metabyte |= 1 << 7
}
switch typ := typ.(type) {
case *types.Basic:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
case *types.Named:
name := typ.Obj().Name()
var pkgpath string
var pkgname string
if pkg := typ.Obj().Pkg(); pkg != nil {
pkgpath = pkg.Path()
pkgname = pkg.Name()
}
pkgPathPtr := c.pkgPathPtr(pkgpath)
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying
pkgPathPtr, // pkgpath pointer
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying
}
metabyte |= 1 << 5 // "named" flag
case *types.Chan:
var dir reflectChanDir
switch typ.Dir() {
case types.SendRecv:
dir = refBothDir
case types.RecvOnly:
dir = refRecvDir
case types.SendOnly:
dir = refSendDir
}
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), uint64(dir), false), // actually channel direction
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType
}
case *types.Slice:
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType
}
case *types.Pointer:
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(typ.Elem()),
}
typeFields = []llvm.Value{c.getTypeCode(typ.Elem())}
case *types.Array:
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType
llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false), // length
c.getTypeCode(types.NewSlice(typ.Elem())), // slicePtr
}
case *types.Map:
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elem
c.getTypeCode(typ.Key()), // key
c.getTypeCode(types.NewPointer(typ)), // ptrTo
}
case *types.Struct:
var pkgpath string
if typ.NumFields() > 0 {
if pkg := typ.Field(0).Pkg(); pkg != nil {
pkgpath = pkg.Path()
}
}
pkgPathPtr := c.pkgPathPtr(pkgpath)
llvmStructType := c.getLLVMType(typ)
size := c.targetData.TypeStoreSize(llvmStructType)
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
pkgPathPtr,
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
c.getTypeCode(types.NewPointer(typ)), // ptrTo
}
structFieldType := c.getLLVMRuntimeType("structField")
var fields []llvm.Value
for i := 0; i < typ.NumFields(); i++ {
field := typ.Field(i)
offset := c.targetData.ElementOffset(llvmStructType, i)
var flags uint8
if field.Anonymous() {
flags |= structFieldFlagAnonymous
@@ -370,14 +213,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
if token.IsExported(field.Name()) {
flags |= structFieldFlagIsExported
}
if field.Embedded() {
flags |= structFieldFlagIsEmbedded
}
var offsBytes [binary.MaxVarintLen32]byte
offLen := binary.PutUvarint(offsBytes[:], offset)
data := string(flags) + string(offsBytes[:offLen]) + field.Name() + "\x00"
data := string(flags) + field.Name() + "\x00"
if typ.Tag(i) != "" {
if len(typ.Tag(i)) > 0xff {
c.addError(field.Pos(), fmt.Sprintf("struct tag is %d bytes which is too long, max is 255", len(typ.Tag(i))))
@@ -418,16 +254,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
}, typeFields...)
}
alignment := c.targetData.TypeAllocSize(c.i8ptrType)
if alignment < 4 {
alignment = 4
}
globalValue := c.ctx.ConstStruct(typeFields, false)
global.SetInitializer(globalValue)
if isLocal {
global.SetLinkage(llvm.InternalLinkage)
} else {
global.SetLinkage(llvm.LinkOnceODRLinkage)
}
global.SetLinkage(llvm.LinkOnceODRLinkage)
global.SetGlobalConstant(true)
global.SetAlignment(int(alignment))
if c.Debug {
@@ -452,8 +281,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
offset = 1
}
return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), offset, false),
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), offset, false),
})
}
@@ -508,94 +337,57 @@ var basicTypeNames = [...]string{
// getTypeCodeName returns a name for this type that can be used in the
// interface lowering pass to assign type codes as expected by the reflect
// package. See getTypeCodeNum.
func getTypeCodeName(t types.Type) (string, bool) {
func getTypeCodeName(t types.Type) string {
switch t := t.(type) {
case *types.Named:
// Note: check for `t.Obj().Pkg() != nil` for Go 1.18 only.
if t.Obj().Pkg() != nil && t.Obj().Parent() != t.Obj().Pkg().Scope() {
return "named:" + t.String() + "$local", true
}
return "named:" + t.String(), false
return "named:" + t.String()
case *types.Array:
s, isLocal := getTypeCodeName(t.Elem())
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + s, isLocal
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
case *types.Basic:
return "basic:" + basicTypeNames[t.Kind()], false
return "basic:" + basicTypeNames[t.Kind()]
case *types.Chan:
s, isLocal := getTypeCodeName(t.Elem())
var dir string
switch t.Dir() {
case types.SendOnly:
dir = "s:"
case types.RecvOnly:
dir = "r:"
case types.SendRecv:
dir = "sr:"
}
return "chan:" + dir + s, isLocal
return "chan:" + getTypeCodeName(t.Elem())
case *types.Interface:
isLocal := false
methods := make([]string, t.NumMethods())
for i := 0; i < t.NumMethods(); i++ {
name := t.Method(i).Name()
if !token.IsExported(name) {
name = t.Method(i).Pkg().Path() + "." + name
}
s, local := getTypeCodeName(t.Method(i).Type())
if local {
isLocal = true
}
methods[i] = name + ":" + s
methods[i] = name + ":" + getTypeCodeName(t.Method(i).Type())
}
return "interface:" + "{" + strings.Join(methods, ",") + "}", isLocal
return "interface:" + "{" + strings.Join(methods, ",") + "}"
case *types.Map:
keyType, keyLocal := getTypeCodeName(t.Key())
elemType, elemLocal := getTypeCodeName(t.Elem())
return "map:" + "{" + keyType + "," + elemType + "}", keyLocal || elemLocal
keyType := getTypeCodeName(t.Key())
elemType := getTypeCodeName(t.Elem())
return "map:" + "{" + keyType + "," + elemType + "}"
case *types.Pointer:
s, isLocal := getTypeCodeName(t.Elem())
return "pointer:" + s, isLocal
return "pointer:" + getTypeCodeName(t.Elem())
case *types.Signature:
isLocal := false
params := make([]string, t.Params().Len())
for i := 0; i < t.Params().Len(); i++ {
s, local := getTypeCodeName(t.Params().At(i).Type())
if local {
isLocal = true
}
params[i] = s
params[i] = getTypeCodeName(t.Params().At(i).Type())
}
results := make([]string, t.Results().Len())
for i := 0; i < t.Results().Len(); i++ {
s, local := getTypeCodeName(t.Results().At(i).Type())
if local {
isLocal = true
}
results[i] = s
results[i] = getTypeCodeName(t.Results().At(i).Type())
}
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}", isLocal
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}"
case *types.Slice:
s, isLocal := getTypeCodeName(t.Elem())
return "slice:" + s, isLocal
return "slice:" + getTypeCodeName(t.Elem())
case *types.Struct:
elems := make([]string, t.NumFields())
isLocal := false
for i := 0; i < t.NumFields(); i++ {
embedded := ""
if t.Field(i).Embedded() {
embedded = "#"
}
s, local := getTypeCodeName(t.Field(i).Type())
if local {
isLocal = true
}
elems[i] = embedded + t.Field(i).Name() + ":" + s
elems[i] = embedded + t.Field(i).Name() + ":" + getTypeCodeName(t.Field(i).Type())
if t.Tag(i) != "" {
elems[i] += "`" + t.Tag(i) + "`"
}
}
return "struct:" + "{" + strings.Join(elems, ",") + "}", isLocal
return "struct:" + "{" + strings.Join(elems, ",") + "}"
default:
panic("unknown type: " + t.String())
}
@@ -679,7 +471,7 @@ func (c *compilerContext) getMethodSignature(method *types.Func) llvm.Value {
// Type asserts on concrete types are trivial: just compare type numbers. Type
// asserts on interfaces are more difficult, see the comments in the function.
func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
itf := b.getValue(expr.X, getPos(expr))
itf := b.getValue(expr.X)
assertedType := b.getLLVMType(expr.AssertedType)
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
@@ -698,8 +490,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
} else {
name, _ := getTypeCodeName(expr.AssertedType)
globalName := "reflect/types.typeid:" + name
globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() {
// Create a new typecode global.
@@ -772,11 +563,10 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
return strings.Join(methods, "; ")
}
// getInterfaceImplementsFunc returns a declared function that works as a type
// getInterfaceImplementsfunc returns a declared function that works as a type
// switch. The interface lowering pass will define this function.
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
s, _ := getTypeCodeName(assertedType.Underlying())
fnName := s + ".$typeassert"
fnName := getTypeCodeName(assertedType.Underlying()) + ".$typeassert"
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.i8ptrType}, false)
@@ -792,8 +582,7 @@ func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) ll
// thunk is declared, not defined: it will be defined by the interface lowering
// pass.
func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
s, _ := getTypeCodeName(instr.Value.Type().Underlying())
fnName := s + "." + instr.Method.Name() + "$invoke"
fnName := getTypeCodeName(instr.Value.Type().Underlying()) + "." + instr.Method.Name() + "$invoke"
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
sig := instr.Method.Type().(*types.Signature)
+1 -1
View File
@@ -24,7 +24,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
// Note that bound functions are allowed if the function has a pointer
// receiver and is a global. This is rather strict but still allows for
// idiomatic Go code.
funcValue := b.getValue(instr.Args[1], getPos(instr))
funcValue := b.getValue(instr.Args[1])
if funcValue.IsAConstant().IsNil() {
// Try to determine the cause of the non-constantness for a nice error
// message.
+14 -135
View File
@@ -58,7 +58,7 @@ func (b *builder) createMemoryCopyImpl() {
}
var params []llvm.Value
for _, param := range b.fn.Params {
params = append(params, b.getValue(param, getPos(b.fn)))
params = append(params, b.getValue(param))
}
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
@@ -70,38 +70,32 @@ func (b *builder) createMemoryCopyImpl() {
// regular libc memset calls if they aren't optimized out in a different way.
func (b *builder) createMemoryZeroImpl() {
b.createFunctionStart(true)
llvmFn := b.getMemsetFunc()
fnName := "llvm.memset.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
if llvmutil.Major() < 15 { // compatibility with LLVM 14
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
params := []llvm.Value{
b.getValue(b.fn.Params[0], getPos(b.fn)),
b.getValue(b.fn.Params[0]),
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
b.getValue(b.fn.Params[1], getPos(b.fn)),
b.getValue(b.fn.Params[1]),
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
b.CreateRetVoid()
}
// Return the llvm.memset.p0.i8 function declaration.
func (c *compilerContext) getMemsetFunc() llvm.Value {
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
if llvmutil.Major() < 15 { // compatibility with LLVM 14
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
}
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
}
return llvmFn
}
// createKeepAlive creates the runtime.KeepAlive function. It is implemented
// using inline assembly.
func (b *builder) createKeepAliveImpl() {
b.createFunctionStart(true)
// Get the underlying value of the interface value.
interfaceValue := b.getValue(b.fn.Params[0], getPos(b.fn))
interfaceValue := b.getValue(b.fn.Params[0])
pointerValue := b.CreateExtractValue(interfaceValue, 1, "")
// Create an equivalent of the following C code, which is basically just a
@@ -155,123 +149,8 @@ func (b *builder) defineMathOp() {
// Create a call to the intrinsic.
args := make([]llvm.Value, len(b.fn.Params))
for i, param := range b.fn.Params {
args[i] = b.getValue(param, getPos(b.fn))
args[i] = b.getValue(param)
}
result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "")
b.CreateRet(result)
}
// Implement most math/bits functions.
//
// This implements all the functions that operate on bits. It does not yet
// implement the arithmetic functions (like bits.Add), which also have LLVM
// intrinsics.
func (b *builder) defineMathBitsIntrinsic() bool {
if b.fn.Pkg.Pkg.Path() != "math/bits" {
return false
}
name := b.fn.Name()
switch name {
case "LeadingZeros", "LeadingZeros8", "LeadingZeros16", "LeadingZeros32", "LeadingZeros64",
"TrailingZeros", "TrailingZeros8", "TrailingZeros16", "TrailingZeros32", "TrailingZeros64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
var intrinsicName string
if strings.HasPrefix(name, "Leading") { // LeadingZeros
intrinsicName = "llvm.ctlz.i" + strconv.Itoa(valueType.IntTypeWidth())
} else { // TrailingZeros
intrinsicName = "llvm.cttz.i" + strconv.Itoa(valueType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
param,
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}, "")
result = b.createZExtOrTrunc(result, b.intType)
b.CreateRet(result)
return true
case "Len", "Len8", "Len16", "Len32", "Len64":
// bits.Len can be implemented as:
// (unsafe.Sizeof(v) * 8) - bits.LeadingZeros(n)
// Not sure why this isn't already done in the standard library, as it
// is much simpler than a lookup table.
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
valueBits := valueType.IntTypeWidth()
intrinsicName := "llvm.ctlz.i" + strconv.Itoa(valueBits)
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
param,
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}, "")
result = b.createZExtOrTrunc(result, b.intType)
maxLen := llvm.ConstInt(b.intType, uint64(valueBits), false) // number of bits in the value
result = b.CreateSub(maxLen, result, "")
b.CreateRet(result)
return true
case "OnesCount", "OnesCount8", "OnesCount16", "OnesCount32", "OnesCount64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
intrinsicName := "llvm.ctpop.i" + strconv.Itoa(valueType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
result = b.createZExtOrTrunc(result, b.intType)
b.CreateRet(result)
return true
case "Reverse", "Reverse8", "Reverse16", "Reverse32", "Reverse64",
"ReverseBytes", "ReverseBytes16", "ReverseBytes32", "ReverseBytes64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
var intrinsicName string
if strings.HasPrefix(name, "ReverseBytes") {
intrinsicName = "llvm.bswap.i" + strconv.Itoa(valueType.IntTypeWidth())
} else { // Reverse
intrinsicName = "llvm.bitreverse.i" + strconv.Itoa(valueType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
b.CreateRet(result)
return true
case "RotateLeft", "RotateLeft8", "RotateLeft16", "RotateLeft32", "RotateLeft64":
// Warning: the documentation says these functions must be constant time.
// I do not think LLVM guarantees this, but there's a good chance LLVM
// already recognized the rotate instruction so it probably won't get
// any _worse_ by implementing these rotate functions.
b.createFunctionStart(true)
x := b.getValue(b.fn.Params[0], b.fn.Pos())
k := b.getValue(b.fn.Params[1], b.fn.Pos())
valueType := x.Type()
intrinsicName := "llvm.fshl.i" + strconv.Itoa(valueType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, valueType, valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
k = b.createZExtOrTrunc(k, valueType)
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{x, x, k}, "")
b.CreateRet(result)
return true
default:
return false
}
}
-13
View File
@@ -464,19 +464,6 @@ func (b *builder) readStackPointer() llvm.Value {
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
}
// createZExtOrTrunc lets the input value fit in the output type bits, by zero
// extending or truncating the integer.
func (b *builder) createZExtOrTrunc(value llvm.Value, t llvm.Type) llvm.Value {
valueBits := value.Type().IntTypeWidth()
resultBits := t.IntTypeWidth()
if valueBits > resultBits {
value = b.CreateTrunc(value, t, "")
} else if valueBits < resultBits {
value = b.CreateZExt(value, t, "")
}
return value
}
// Reverse a slice of bytes. From the wiki:
// https://github.com/golang/go/wiki/SliceTricks#reversing
func reverseBytes(buf []byte) {
+5 -90
View File
@@ -46,7 +46,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil {
sizeHint = b.getValue(expr.Reserve, getPos(expr))
sizeHint = b.getValue(expr.Reserve)
var err error
sizeHint, err = b.createConvert(expr.Reserve.Type(), types.Typ[types.Uintptr], sizeHint, expr.Pos())
if err != nil {
@@ -78,7 +78,6 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
// Do the lookup. How it is done depends on the key type.
var commaOkValue llvm.Value
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
@@ -90,7 +89,6 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
// growth.
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, mapKeyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
// Fetch the value from the hashmap.
params := []llvm.Value{m, mapKeyPtr, mapValuePtr, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
@@ -100,7 +98,7 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface now.
itfKey = b.createMakeInterface(key, origKeyType, pos)
itfKey = b.createMakeInterface(key, keyType, pos)
}
params := []llvm.Value{m, itfKey, mapValuePtr, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
@@ -126,7 +124,6 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
valueAlloca, valuePtr, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
b.CreateStore(value, valueAlloca)
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
@@ -136,7 +133,6 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
// key can be compared with runtime.memequal
keyAlloca, keyPtr, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
params := []llvm.Value{m, keyPtr, valuePtr}
b.createRuntimeCall("hashmapBinarySet", params, "")
b.emitLifetimeEnd(keyPtr, keySize)
@@ -145,7 +141,7 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface first.
itfKey = b.createMakeInterface(key, origKeyType, pos)
itfKey = b.createMakeInterface(key, keyType, pos)
}
params := []llvm.Value{m, itfKey, valuePtr}
b.createRuntimeCall("hashmapInterfaceSet", params, "")
@@ -156,7 +152,6 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
// createMapDelete deletes a key from a map by calling the appropriate runtime
// function. It is the implementation of the Go delete() builtin.
func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
origKeyType := keyType
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
@@ -166,7 +161,6 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
} else if hashmapIsBinaryKey(keyType) {
keyAlloca, keyPtr, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
params := []llvm.Value{m, keyPtr}
b.createRuntimeCall("hashmapBinaryDelete", params, "")
b.emitLifetimeEnd(keyPtr, keySize)
@@ -177,7 +171,7 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
itfKey := key
if _, ok := keyType.(*types.Interface); !ok {
// Not already an interface, so convert it to an interface first.
itfKey = b.createMakeInterface(key, origKeyType, pos)
itfKey = b.createMakeInterface(key, keyType, pos)
}
params := []llvm.Value{m, itfKey}
b.createRuntimeCall("hashmapInterfaceDelete", params, "")
@@ -185,11 +179,6 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
}
}
// Clear the given map.
func (b *builder) createMapClear(m llvm.Value) {
b.createRuntimeCall("hashmapClear", []llvm.Value{m}, "")
}
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
// map. It returns a tuple of {bool, key, value} with the result of the
// iteration.
@@ -251,8 +240,7 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
}
// Returns true if this key type does not contain strings, interfaces etc., so
// can be compared with runtime.memequal. Note that padding bytes are undef
// and can alter two "equal" structs being equal when compared with memequal.
// can be compared with runtime.memequal.
func hashmapIsBinaryKey(keyType types.Type) bool {
switch keyType := keyType.(type) {
case *types.Basic:
@@ -275,76 +263,3 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
return false
}
}
func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
// We know that hashmapIsBinaryKey is true, so we only have to handle those types that can show up there.
// To zero all undefined bytes, we iterate over all the fields in the type. For each element, compute the
// offset of that element. If it's Basic type, there are no internal padding bytes. For compound types, we recurse to ensure
// we handle nested types. Next, we determine if there are any padding bytes before the next
// element and zero those as well.
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
switch llvmType.TypeKind() {
case llvm.IntegerTypeKind:
// no padding bytes
return nil
case llvm.PointerTypeKind:
// mo padding bytes
return nil
case llvm.ArrayTypeKind:
llvmArrayType := llvmType
llvmElemType := llvmType.ElementType()
for i := 0; i < llvmArrayType.ArrayLength(); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
elemPtr := b.CreateInBoundsGEP(llvmArrayType, ptr, []llvm.Value{zero, idx}, "")
// zero any padding bytes in this element
b.zeroUndefBytes(llvmElemType, elemPtr)
}
case llvm.StructTypeKind:
llvmStructType := llvmType
numFields := llvmStructType.StructElementTypesCount()
llvmElementTypes := llvmStructType.StructElementTypes()
for i := 0; i < numFields; i++ {
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
elemPtr := b.CreateInBoundsGEP(llvmStructType, ptr, []llvm.Value{zero, idx}, "")
// zero any padding bytes in this field
llvmElemType := llvmElementTypes[i]
b.zeroUndefBytes(llvmElemType, elemPtr)
// zero any padding bytes before the next field, if any
offset := b.targetData.ElementOffset(llvmStructType, i)
storeSize := b.targetData.TypeStoreSize(llvmElemType)
fieldEndOffset := offset + storeSize
var nextOffset uint64
if i < numFields-1 {
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
} else {
// Last field? Next offset is the total size of the allcoate struct.
nextOffset = b.targetData.TypeAllocSize(llvmStructType)
}
if fieldEndOffset != nextOffset {
n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
gepPtr := elemPtr
if gepPtr.Type() != b.i8ptrType {
gepPtr = b.CreateBitCast(gepPtr, b.i8ptrType, "") // LLVM 14
}
paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), gepPtr, []llvm.Value{llvmStoreSize}, "")
if paddingStart.Type() != b.i8ptrType {
paddingStart = b.CreateBitCast(paddingStart, b.i8ptrType, "") // LLVM 14
}
b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
}
}
}
return nil
}
+34 -110
View File
@@ -4,7 +4,6 @@ package compiler
// pragmas, determines the link name, etc.
import (
"fmt"
"go/ast"
"go/token"
"go/types"
@@ -23,9 +22,9 @@ 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
linkName string // go:linkname, go:export - the IR function name
module string // go:wasm-module
importName string // go:linkname, go:export - The name the developer assigns
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
section string // go:section - object file section name
exported bool // go:export, CGo
interrupt bool // go:interrupt
@@ -53,17 +52,6 @@ const (
inlineNone
)
// Values for the allockind attribute. Source:
// https://github.com/llvm/llvm-project/blob/release/16.x/llvm/include/llvm/IR/Attributes.h#L49
const (
allocKindAlloc = 1 << iota
allocKindRealloc
allocKindFree
allocKindUninitialized
allocKindZeroed
allocKindAligned
)
// getFunction returns the LLVM function for the given *ssa.Function, creating
// it if needed. It can later be filled with compilerContext.createFunction().
func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) {
@@ -145,20 +133,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
for _, attrName := range []string{"noalias", "nonnull"} {
llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
}
if llvmutil.Major() >= 15 { // allockind etc are not available in LLVM 14
// Add attributes to signal to LLVM that this is an allocator
// function. This enables a number of optimizations.
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allockind"), allocKindAlloc|allocKindZeroed))
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("alloc-family", "runtime.alloc"))
// Use a special value to indicate the first parameter:
// > allocsize has two integer arguments, but because they're both 32 bits, we can
// > pack them into one 64-bit value, at the cost of making said value
// > nonsensical.
// >
// > In order to do this, we need to reserve one value of the second (optional)
// > allocsize argument to signify "not present."
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allocsize"), 0x0000_0000_ffff_ffff))
}
case "runtime.sliceAppend":
// Appending a slice will only read the to-be-appended slice, it won't
// be modified.
@@ -180,7 +154,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
if strings.Split(c.Triple, "-")[0] == "avr" {
// These functions are compiler-rt/libgcc functions that are
// currently implemented in Go. Assembly versions should appear in
// LLVM 17 hopefully. Until then, they need to be made available to
// LLVM 16 hopefully. Until then, they need to be made available to
// the linker and the best way to do that is llvm.compiler.used.
// I considered adding a pragma for this, but the LLVM language
// reference explicitly says that this feature should not be exposed
@@ -194,14 +168,20 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// External/exported functions may not retain pointer values.
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
if info.exported {
if c.archFamily() == "wasm32" && len(fn.Blocks) == 0 {
if c.archFamily() == "wasm32" {
// We need to add the wasm-import-module and the wasm-import-name
// attributes.
if info.wasmModule != "" {
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", info.wasmModule))
module := info.module
if module == "" {
module = "env"
}
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
name := info.importName
if name == "" {
name = info.linkName
}
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
}
nocaptureKind := llvm.AttributeKindID("nocapture")
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
@@ -234,26 +214,26 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// present in *ssa.Function, such as the link name and whether it should be
// exported.
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
if info, ok := c.functionInfos[f]; ok {
return info
}
info := functionInfo{
// Pick the default linkName.
linkName: f.RelString(nil),
}
// Check for //go: pragmas, which may change the link name (among others).
c.parsePragmas(&info, f)
c.functionInfos[f] = info
info.parsePragmas(f)
return info
}
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
// //export or //go:noinline.
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
func (info *functionInfo) parsePragmas(f *ssa.Function) {
if f.Syntax() == nil {
return
}
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
// Our importName for a wasm module (if we are compiling to wasm), or llvm link name
var importName string
for _, comment := range decl.Doc.List {
text := comment.Text
if strings.HasPrefix(text, "//export ") {
@@ -271,8 +251,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
continue
}
info.linkName = parts[1]
info.wasmName = info.linkName
importName = parts[1]
info.exported = true
case "//go:interrupt":
if hasUnsafeImport(f.Pkg.Pkg) {
@@ -280,22 +259,10 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
}
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]
info.module = parts[1]
case "//go:inline":
info.inline = inlineHint
case "//go:noinline":
@@ -312,12 +279,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
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
@@ -339,59 +302,18 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
}
}
}
}
}
// 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) checkWasmImport(f *ssa.Function, pragma string) {
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
// 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 !isValidWasmType(result.Type(), true) {
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 !isValidWasmType(param.Type(), false) {
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
}
}
}
// Check whether the type maps directly to a WebAssembly type, according to:
// https://github.com/golang/go/issues/59149
func isValidWasmType(typ types.Type, isReturn bool) bool {
switch typ := typ.Underlying().(type) {
case *types.Basic:
switch typ.Kind() {
case types.Int32, types.Uint32, types.Int64, types.Uint64:
return true
case types.Float32, types.Float64:
return true
case types.UnsafePointer:
if !isReturn {
return true
// Set the importName for our exported function if we have one
if importName != "" {
if info.module == "" {
info.linkName = importName
} else {
// WebAssembly import
info.importName = importName
}
}
}
return false
}
// getParams returns the function parameters, including the receiver at the
@@ -457,7 +379,7 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
}
}
// addStandardAttributes adds all attributes added to defined functions.
// addStandardAttribute adds all attributes added to defined functions.
func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
c.addStandardDeclaredAttributes(llvmFn)
c.addStandardDefinedAttributes(llvmFn)
@@ -511,6 +433,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName)
// Set alignment from the //go:align comment.
var alignInBits uint32
alignment := c.targetData.ABITypeAlignment(llvmType)
if info.align > alignment {
alignment = info.align
@@ -521,6 +444,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
c.addError(g.Pos(), "global variable alignment must be a positive power of two")
} else {
// Set the alignment only when it is a power of two.
alignInBits = uint32(alignment) ^ uint32(alignment-1)
llvmGlobal.SetAlignment(alignment)
}
@@ -535,7 +459,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
Type: c.getDIType(typ),
LocalToUnit: false,
Expr: c.dibuilder.CreateExpression(nil),
AlignInBits: uint32(alignment) * 8,
AlignInBits: alignInBits,
})
llvmGlobal.AddMetadata(0, diglobal)
}
+7 -7
View File
@@ -14,7 +14,7 @@ import (
// and returns the result as a single integer (the system call result). The
// result is not further interpreted.
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
num := b.getValue(call.Args[0], getPos(call))
num := b.getValue(call.Args[0])
switch {
case b.GOARCH == "amd64" && b.GOOS == "linux":
// Sources:
@@ -37,7 +37,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
"{r12}",
"{r13}",
}[i]
llvmValue := b.getValue(arg, getPos(call))
llvmValue := b.getValue(arg)
args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -64,7 +64,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
"{edi}",
"{ebp}",
}[i]
llvmValue := b.getValue(arg, getPos(call))
llvmValue := b.getValue(arg)
args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -89,7 +89,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
"{r5}",
"{r6}",
}[i]
llvmValue := b.getValue(arg, getPos(call))
llvmValue := b.getValue(arg)
args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -119,7 +119,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
"{x4}",
"{x5}",
}[i]
llvmValue := b.getValue(arg, getPos(call))
llvmValue := b.getValue(arg)
args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -177,12 +177,12 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
var paramTypes []llvm.Type
var params []llvm.Value
for _, val := range call.Args[2:] {
param := b.getValue(val, getPos(call))
param := b.getValue(val)
params = append(params, param)
paramTypes = append(paramTypes, param.Type())
}
llvmType := llvm.FunctionType(b.uintptrType, paramTypes, false)
fn := b.getValue(call.Args[0], getPos(call))
fn := b.getValue(call.Args[0])
fnPtr := b.CreateIntToPtr(fn, llvm.PointerType(llvmType, 0), "")
// Prepare some functions that will be called later.
+38 -31
View File
@@ -10,33 +10,32 @@ target triple = "wasm32-unknown-wasi"
@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.b = hidden global [2 x ptr] zeroinitializer, align 4
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = add i32 %x, %y
ret i32 %0
}
; Function Attrs: nounwind
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq i32 %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -50,14 +49,14 @@ divbyzero.next: ; preds = %entry
ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #3
call void @runtime.divideByZeroPanic(ptr undef) #2
unreachable
}
declare void @runtime.divideByZeroPanic(ptr) #1
declare void @runtime.divideByZeroPanic(ptr) #0
; Function Attrs: nounwind
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -67,12 +66,12 @@ divbyzero.next: ; preds = %entry
ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #3
call void @runtime.divideByZeroPanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -86,12 +85,12 @@ divbyzero.next: ; preds = %entry
ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #3
call void @runtime.divideByZeroPanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -101,66 +100,66 @@ divbyzero.next: ; preds = %entry
ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #3
call void @runtime.divideByZeroPanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp oeq float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp une float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp olt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp ole float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp ogt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 {
entry:
%0 = fcmp oge float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
entry:
ret float %x.r
}
; Function Attrs: nounwind
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 {
entry:
ret float %x.i
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
entry:
%0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i
@@ -170,7 +169,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 +179,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 +193,27 @@ 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:
%complit = alloca %main.kv.0, align 8
%stackalloc = alloca i8, align 1
store %main.kv.0 zeroinitializer, ptr %complit, align 8
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #2
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:
%b1 = alloca %main.kv.0, align 8
%stackalloc = alloca i8, align 1
store %main.kv.0 zeroinitializer, ptr %b1, align 8
call void @runtime.trackPointer(ptr nonnull %b1, ptr nonnull %stackalloc, ptr undef) #2
store %main.kv.0 %b, ptr %b1, align 8
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 = { nounwind }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
+26 -25
View File
@@ -6,76 +6,78 @@ target triple = "wasm32-unknown-wasi"
%runtime.channelBlockedList = type { ptr, ptr, ptr, { ptr, i32, i32 } }
%runtime.chanSelectState = type { ptr, ptr }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(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
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
store i32 3, ptr %chan.value, align 4
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #3
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
ret void
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
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) #0
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
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
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #4
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.blockedList, ptr undef) #3
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
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) #0
; 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:
%complit = alloca {}, align 8
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList)
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #3
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
ret void
}
; 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)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #4
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.blockedList, ptr undef) #3
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %chan.blockedList)
ret void
}
; 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
@@ -88,7 +90,7 @@ entry:
store ptr %ch2, ptr %0, align 8
%.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
store ptr null, ptr %.repack3, align 4
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #3
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
%1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0
@@ -105,10 +107,9 @@ 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) #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 #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { argmemonly nocallback nofree nosync nounwind willreturn }
attributes #3 = { nounwind }
+33 -47
View File
@@ -7,7 +7,6 @@ target triple = "thumbv7m-unknown-unknown-eabi"
%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
@@ -16,7 +15,7 @@ entry:
ret void
}
declare void @main.external(ptr) #2
declare void @main.external(ptr) #0
; Function Attrs: nounwind
define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
@@ -26,27 +25,20 @@ entry:
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4
%0 = call ptr @llvm.stacksave()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #3
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
store ptr %defer.alloca, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result = icmp eq i32 %setjmp, 0
br i1 %setjmp.result, label %1, label %lpad
1: ; preds = %entry
call void @main.external(ptr undef) #4
br label %rundefers.block
rundefers.after: ; preds = %rundefers.end
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
ret void
rundefers.block: ; preds = %1
call void @main.external(ptr undef) #3
br label %rundefers.loophead
rundefers.loophead: ; preds = %3, %rundefers.block
rundefers.loophead: ; preds = %3, %1
%2 = load ptr, ptr %deferPtr, align 4
%stackIsNil = icmp eq ptr %2, null
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
@@ -61,7 +53,7 @@ rundefers.loop: ; preds = %rundefers.loophead
]
rundefers.callback0: ; preds = %rundefers.loop
%setjmp1 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp1 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result2 = icmp eq i32 %setjmp1, 0
br i1 %setjmp.result2, label %3, label %lpad
@@ -73,10 +65,11 @@ rundefers.default: ; preds = %rundefers.loop
unreachable
rundefers.end: ; preds = %rundefers.loophead
br label %rundefers.after
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
ret void
recover: ; preds = %rundefers.end3
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
ret void
lpad: ; preds = %rundefers.callback012, %rundefers.callback0, %entry
@@ -97,7 +90,7 @@ rundefers.loop5: ; preds = %rundefers.loophead6
]
rundefers.callback012: ; preds = %rundefers.loop5
%setjmp13 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp13 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result14 = icmp eq i32 %setjmp13, 0
br i1 %setjmp.result14, label %5, label %lpad
@@ -113,20 +106,20 @@ rundefers.end3: ; preds = %rundefers.loophead6
}
; Function Attrs: nocallback nofree nosync nounwind willreturn
declare ptr @llvm.stacksave() #3
declare ptr @llvm.stacksave() #2
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #0
; Function Attrs: nounwind
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printint32(i32 3, ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #3
ret void
}
declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #0
declare void @runtime.printint32(i32, ptr) #0
; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
@@ -137,7 +130,7 @@ entry:
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4
%0 = call ptr @llvm.stacksave()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #3
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
@@ -146,22 +139,15 @@ entry:
%defer.alloca2.repack23 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca2, i32 0, i32 1
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
store ptr %defer.alloca2, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result = icmp eq i32 %setjmp, 0
br i1 %setjmp.result, label %1, label %lpad
1: ; preds = %entry
call void @main.external(ptr undef) #4
br label %rundefers.block
rundefers.after: ; preds = %rundefers.end
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
ret void
rundefers.block: ; preds = %1
call void @main.external(ptr undef) #3
br label %rundefers.loophead
rundefers.loophead: ; preds = %4, %3, %rundefers.block
rundefers.loophead: ; preds = %4, %3, %1
%2 = load ptr, ptr %deferPtr, align 4
%stackIsNil = icmp eq ptr %2, null
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
@@ -177,7 +163,7 @@ rundefers.loop: ; preds = %rundefers.loophead
]
rundefers.callback0: ; preds = %rundefers.loop
%setjmp3 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp3 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result4 = icmp eq i32 %setjmp3, 0
br i1 %setjmp.result4, label %3, label %lpad
@@ -186,7 +172,7 @@ rundefers.callback0: ; preds = %rundefers.loop
br label %rundefers.loophead
rundefers.callback1: ; preds = %rundefers.loop
%setjmp5 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp5 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result6 = icmp eq i32 %setjmp5, 0
br i1 %setjmp.result6, label %4, label %lpad
@@ -198,10 +184,11 @@ rundefers.default: ; preds = %rundefers.loop
unreachable
rundefers.end: ; preds = %rundefers.loophead
br label %rundefers.after
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
ret void
recover: ; preds = %rundefers.end7
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #3
ret void
lpad: ; preds = %rundefers.callback119, %rundefers.callback016, %rundefers.callback1, %rundefers.callback0, %entry
@@ -223,7 +210,7 @@ rundefers.loop9: ; preds = %rundefers.loophead1
]
rundefers.callback016: ; preds = %rundefers.loop9
%setjmp17 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp17 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result18 = icmp eq i32 %setjmp17, 0
br i1 %setjmp.result18, label %6, label %lpad
@@ -232,7 +219,7 @@ rundefers.callback016: ; preds = %rundefers.loop9
br label %rundefers.loophead10
rundefers.callback119: ; preds = %rundefers.loop9
%setjmp20 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
%setjmp20 = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #4
%setjmp.result21 = icmp eq i32 %setjmp20, 0
br i1 %setjmp.result21, label %7, label %lpad
@@ -250,20 +237,19 @@ rundefers.end7: ; preds = %rundefers.loophead1
; Function Attrs: nounwind
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printint32(i32 3, ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #3
ret void
}
; Function Attrs: nounwind
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
entry:
call void @runtime.printint32(i32 5, ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #3
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { nounwind }
attributes #5 = { nounwind returns_twice }
attributes #2 = { nocallback nofree nosync nounwind willreturn }
attributes #3 = { nounwind }
attributes #4 = { nounwind returns_twice }
-43
View File
@@ -1,43 +0,0 @@
package main
import "unsafe"
//go:wasmimport modulename empty
func empty()
// ERROR: can only use //go:wasmimport on declarations
//
//go:wasmimport modulename implementation
func implementation() {
}
type Uint uint32
//go:wasmimport modulename validparam
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
//
//go:wasmimport modulename invalidparam
func invalidparam(a int, b string, c []byte, d *int32)
//go:wasmimport modulename validreturn
func validreturn() int32
// ERROR: //go:wasmimport modulename manyreturns: too many return values
//
//go:wasmimport modulename manyreturns
func manyreturns() (int32, int32)
// ERROR: //go:wasmimport modulename invalidreturn: unsupported result type int
//
//go:wasmimport modulename invalidreturn
func invalidreturn() int
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
//
//go:wasmimport modulename invalidUnsafePointerReturn
func invalidUnsafePointerReturn() unsafe.Pointer
+12 -14
View File
@@ -3,19 +3,18 @@ source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -27,25 +26,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 +54,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 +67,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 +79,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 +92,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 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
+11 -13
View File
@@ -3,48 +3,46 @@ source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp eq ptr %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.next: ; preds = %entry
call void %callback.funcptr(i32 3, ptr %callback.context) #3
call void %callback.funcptr(i32 3, ptr %callback.context) #2
ret void
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(ptr undef) #3
call void @runtime.nilPanic(ptr undef) #2
unreachable
}
declare void @runtime.nilPanic(ptr) #1
declare void @runtime.nilPanic(ptr) #0
; Function Attrs: nounwind
define hidden void @main.bar(ptr %context) unnamed_addr #2 {
define hidden void @main.bar(ptr %context) unnamed_addr #1 {
entry:
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 {
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 {
entry:
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
+47 -49
View File
@@ -21,99 +21,98 @@ target triple = "wasm32-unknown-wasi"
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 16, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:complex128" }, align 4
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%new = call 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 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) #2
store ptr %new, ptr @main.scalar1, align 4
%new1 = call 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 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) #2
store ptr %new1, ptr @main.scalar2, align 4
%new2 = call 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 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) #2
store ptr %new2, ptr @main.scalar3, align 4
%new3 = call 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 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) #2
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 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 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) #2
store ptr %new, ptr @main.array1, align 4
%new1 = call 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 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) #2
store ptr %new1, ptr @main.array2, align 4
%new2 = call 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 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) #2
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 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 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) #2
store ptr %new, ptr @main.struct1, align 4
%new1 = call 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 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) #2
store ptr %new1, ptr @main.struct2, align 4
%new2 = call 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 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) #2
store ptr %new2, ptr @main.struct3, align 4
%new3 = call 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 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) #2
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 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 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) #2
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 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 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) #2
store ptr %makeslice, ptr @main.slice1, align 8
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 8
%makeslice1 = call dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
%makeslice1 = call 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) #2
store ptr %makeslice1, ptr @main.slice2, align 8
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 8
%makeslice3 = call dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
%makeslice3 = call 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) #2
store ptr %makeslice3, ptr @main.slice3, align 8
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 8
@@ -121,21 +120,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 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 ptr @runtime.alloc(i32 16, ptr null, ptr undef) #2
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
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) #2
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
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 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
+13 -15
View File
@@ -5,27 +5,26 @@ target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %s.data
}
; Function Attrs: nounwind
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp slt i16 %len, 0
@@ -39,25 +38,24 @@ 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) #2
ret %runtime._string %7
unsafe.String.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #3
call void @runtime.unsafeSlicePanic(ptr undef) #2
unreachable
}
declare void @runtime.unsafeSlicePanic(ptr) #1
declare void @runtime.unsafeSlicePanic(ptr) #0
; Function Attrs: nounwind
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %s.data
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
-65
View File
@@ -1,65 +0,0 @@
package main
func min1(a int) int {
return min(a)
}
func min2(a, b int) int {
return min(a, b)
}
func min3(a, b, c int) int {
return min(a, b, c)
}
func min4(a, b, c, d int) int {
return min(a, b, c, d)
}
func minUint8(a, b uint8) uint8 {
return min(a, b)
}
func minUnsigned(a, b uint) uint {
return min(a, b)
}
func minFloat32(a, b float32) float32 {
return min(a, b)
}
func minFloat64(a, b float64) float64 {
return min(a, b)
}
func minString(a, b string) string {
return min(a, b)
}
func maxInt(a, b int) int {
return max(a, b)
}
func maxUint(a, b uint) uint {
return max(a, b)
}
func maxFloat32(a, b float32) float32 {
return max(a, b)
}
func maxString(a, b string) string {
return max(a, b)
}
func clearSlice(s []int) {
clear(s)
}
func clearZeroSizedSlice(s []struct{}) {
clear(s)
}
func clearMap(m map[string]int) {
clear(m)
}
-179
View File
@@ -1,179 +0,0 @@
; ModuleID = 'go1.21.go'
source_filename = "go1.21.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 }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
entry:
ret i32 %a
}
; Function Attrs: nounwind
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
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 {
entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
ret i32 %1
}
; Function Attrs: nounwind
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
%2 = call i32 @llvm.smin.i32(i32 %1, i32 %d)
ret i32 %2
}
; Function Attrs: nounwind
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
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 {
entry:
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nounwind
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp olt float %a, %b
%1 = select i1 %0, float %a, float %b
ret float %1
}
; Function Attrs: nounwind
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp olt double %a, %b
%1 = select i1 %0, double %a, double %b
ret double %1
}
; 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 {
entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
%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
ret %runtime._string %5
}
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
; Function Attrs: nounwind
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
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 {
entry:
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
ret i32 %0
}
; Function Attrs: nounwind
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry:
%0 = fcmp ogt float %a, %b
%1 = select i1 %0, float %a, float %b
ret float %1
}
; Function Attrs: nounwind
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
%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
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 {
entry:
%0 = shl i32 %s.len, 2
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
ret void
}
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
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 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
entry:
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
ret void
}
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smin.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.umin.i8(i8, i8) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #4
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 nounwind willreturn memory(argmem: write) }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #5 = { nounwind }
+40 -42
View File
@@ -7,7 +7,6 @@ target triple = "thumbv7m-unknown-unknown-eabi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
; Function Attrs: nounwind
@@ -19,30 +18,30 @@ entry:
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #8
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #8
ret void
}
declare void @main.regularFunction(i32, ptr) #2
declare void @main.regularFunction(i32, ptr) #0
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
call void @main.regularFunction(i32 %unpack.int, ptr undef) #8
ret void
}
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #2
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #0
declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #9
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #8
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #8
ret void
}
@@ -53,7 +52,7 @@ entry:
}
; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
@@ -63,16 +62,16 @@ entry:
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
%n = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #8
store i32 3, ptr %n, align 4
%0 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
%0 = call ptr @runtime.alloc(i32 8, ptr null, ptr undef) #8
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
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #8
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #8
%2 = load i32, ptr %n, align 4
call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #8
ret void
}
@@ -84,7 +83,7 @@ entry:
}
; Function Attrs: nounwind
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
@@ -93,31 +92,31 @@ entry:
ret void
}
declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printint32(i32, ptr) #0
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry:
%0 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
%0 = call ptr @runtime.alloc(i32 12, ptr null, ptr undef) #8
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
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
store ptr %fn.funcptr, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #8
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #8
ret void
}
; Function Attrs: nounwind
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9
call void %5(i32 %1, ptr %3) #8
ret void
}
@@ -130,25 +129,25 @@ entry:
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
entry:
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #8
ret void
}
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2
declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #0
; Function Attrs: nounwind
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
call void @runtime.chanClose(ptr %ch, ptr undef) #8
ret void
}
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #0
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
%0 = call ptr @runtime.alloc(i32 16, ptr null, ptr undef) #8
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4
@@ -156,15 +155,15 @@ entry:
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
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #8
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) #8
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #6
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #7 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
@@ -173,17 +172,16 @@ entry:
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
%7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #8
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
attributes #7 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #8 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #9 = { nounwind }
attributes #2 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" }
attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper" }
attributes #6 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #7 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #8 = { nounwind }
+59 -61
View File
@@ -7,159 +7,158 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #8
ret void
}
declare void @main.regularFunction(i32, ptr) #1
declare void @main.regularFunction(i32, ptr) #0
declare void @runtime.deadlock(ptr) #1
declare void @runtime.deadlock(ptr) #0
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #9
call void @runtime.deadlock(ptr undef) #9
call void @main.regularFunction(i32 %unpack.int, ptr undef) #8
call void @runtime.deadlock(ptr undef) #8
unreachable
}
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 16384, ptr undef) #8
ret void
}
; Function Attrs: nounwind
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 {
entry:
%unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
call void @runtime.deadlock(ptr undef) #9
call void @runtime.deadlock(ptr undef) #8
unreachable
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
%n = call ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #8
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #8
store i32 3, ptr %n, align 4
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
%0 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #8
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #8
%0 = call ptr @runtime.alloc(i32 8, ptr null, ptr undef) #8
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
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
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 32768, ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 16384, ptr undef) #8
%2 = load i32, ptr %n, align 4
call void @runtime.printint32(i32 %2, ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #8
ret void
}
; 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
}
; Function Attrs: nounwind
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
call void @runtime.deadlock(ptr undef) #9
call void @runtime.deadlock(ptr undef) #8
unreachable
}
declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printint32(i32, ptr) #0
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
%0 = call ptr @runtime.alloc(i32 12, ptr null, ptr undef) #8
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
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
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
store ptr %fn.funcptr, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 32768, ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 16384, ptr undef) #8
ret void
}
; Function Attrs: nounwind
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9
call void @runtime.deadlock(ptr undef) #9
call void %5(i32 %1, ptr %3) #8
call void @runtime.deadlock(ptr undef) #8
unreachable
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
entry:
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #8
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) #0
; 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
call void @runtime.chanClose(ptr %ch, ptr undef) #8
ret void
}
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1
declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #0
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
%0 = call ptr @runtime.alloc(i32 16, ptr null, ptr undef) #8
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #8
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
store ptr @"main$string", ptr %1, align 4
@@ -167,14 +166,14 @@ entry:
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 32768, ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 16384, ptr undef) #8
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #7
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i32, ptr, ptr) #6
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #7 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
@@ -183,18 +182,17 @@ entry:
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
%7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
call void @runtime.deadlock(ptr undef) #9
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #8
call void @runtime.deadlock(ptr undef) #8
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 #9 = { nounwind }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #4 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" }
attributes #6 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #7 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #8 = { nounwind }
+45 -48
View File
@@ -6,68 +6,66 @@ target triple = "wasm32-unknown-wasi"
%runtime._interface = type { ptr, ptr }
%runtime._string = type { ptr, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 0, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.typeid:basic:int" = external constant i8
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #6
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #6
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
}
; Function Attrs: nounwind
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #6
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -77,12 +75,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #0
; Function Attrs: nounwind
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -92,12 +90,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #2
; Function Attrs: nounwind
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
@@ -107,34 +105,33 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next
}
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #3
; Function Attrs: nounwind
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #6
ret i8 %0
}
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #4
; Function Attrs: nounwind
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #6
%1 = extractvalue %runtime._string %0, 0
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #6
ret %runtime._string %0
}
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #5
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 #7 = { nounwind }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
attributes #3 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
attributes #4 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
attributes #5 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
attributes #6 = { nounwind }
+15
View File
@@ -24,3 +24,18 @@ func pointerCastToUnsafe(x *int) unsafe.Pointer {
func pointerCastToUnsafeNoop(x *byte) unsafe.Pointer {
return unsafe.Pointer(x)
}
// The compiler has support for a few special cast+add patterns that are
// transformed into a single GEP.
func pointerUnsafeGEPFixedOffset(ptr *byte) *byte {
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + 10))
}
func pointerUnsafeGEPByteOffset(ptr *byte, offset uintptr) *byte {
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset))
}
func pointerUnsafeGEPIntOffset(ptr *int32, offset uintptr) *int32 {
return (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset*4))
}
+46 -14
View File
@@ -3,48 +3,80 @@ source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 {
entry:
ret [0 x i32] zeroinitializer
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %x
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %x
}
; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %x
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 }
; Function Attrs: nounwind
define hidden ptr @main.pointerUnsafeGEPFixedOffset(ptr dereferenceable_or_null(1) %ptr, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
%0 = getelementptr inbounds i8, ptr %ptr, i32 10
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %0
}
; Function Attrs: nounwind
define hidden ptr @main.pointerUnsafeGEPByteOffset(ptr dereferenceable_or_null(1) %ptr, i32 %offset, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
%0 = getelementptr inbounds i8, ptr %ptr, i32 %offset
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %0
}
; Function Attrs: nounwind
define hidden ptr @main.pointerUnsafeGEPIntOffset(ptr dereferenceable_or_null(4) %ptr, i32 %offset, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
%0 = shl i32 %offset, 2
%1 = getelementptr inbounds i8, ptr %ptr, i32 %0
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #2
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #2
ret ptr %1
}
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
-16
View File
@@ -59,22 +59,6 @@ func functionInSection() {
func exportedFunctionInSection() {
}
//go:wasmimport modulename import1
func declaredImport()
// Legacy way of importing a function.
//
//go:wasm-module foobar
//export imported
func foobarImport()
// The wasm-module pragma is not functional here, but it should be safe.
//
//go:wasm-module foobar
//export exported
func foobarExportModule() {
}
// This function should not: it's only a declaration and not a definition.
//
//go:section .special_function_section
+22 -37
View File
@@ -6,79 +6,64 @@ target triple = "wasm32-unknown-wasi"
@extern_global = external global [0 x i8], align 1
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
@llvm.used = appending global [3 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection, ptr @exported]
@llvm.used = appending global [2 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection]
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
@undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define void @extern_func() #3 {
define void @extern_func() #2 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 {
entry:
ret void
}
declare void @somepkg.someFunction2(ptr) #1
declare void @somepkg.someFunction2(ptr) #0
; Function Attrs: inlinehint nounwind
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #3 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #5 {
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #4 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
entry:
ret void
}
; Function Attrs: noinline nounwind
define void @exportedFunctionInSection() #6 section ".special_function_section" {
entry:
ret void
}
declare void @main.declaredImport() #7
declare void @imported() #8
; Function Attrs: nounwind
define void @exported() #9 {
define hidden void @main.functionInSection(ptr %context) unnamed_addr #1 section ".special_function_section" {
entry:
ret void
}
declare void @main.undefinedFunctionNotInSection(ptr) #1
; Function Attrs: nounwind
define void @exportedFunctionInSection() #5 section ".special_function_section" {
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 = { 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" }
declare void @main.undefinedFunctionNotInSection(ptr) #0
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
+62 -64
View File
@@ -3,31 +3,30 @@ source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
entry:
ret i32 %ints.len
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 {
entry:
ret i32 %ints.cap
}
; Function Attrs: nounwind
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 {
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 {
entry:
%.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw
@@ -38,84 +37,84 @@ lookup.next: ; preds = %entry
ret i32 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #3
call void @runtime.lookupPanic(ptr undef) #2
unreachable
}
declare void @runtime.lookupPanic(ptr) #1
declare void @runtime.lookupPanic(ptr) #0
; Function Attrs: nounwind
define hidden { 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 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
%varargs = call ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #2
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
%1 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 2
store i32 3, ptr %1, align 4
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #2
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1
%4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #2
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) #0
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #2
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
%0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0
%1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #2
ret { ptr, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 {
define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 {
entry:
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3
%copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #2
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) #0
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.next: ; preds = %entry
%makeslice.buf = call ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%makeslice.buf = call ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
%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) #2
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #3
call void @runtime.slicePanic(ptr undef) #2
unreachable
}
declare void @runtime.slicePanic(ptr) #1
declare void @runtime.slicePanic(ptr) #0
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0
@@ -123,20 +122,20 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 1
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
%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) #2
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #3
call void @runtime.slicePanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1431655765
@@ -144,20 +143,20 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
%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) #2
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #3
call void @runtime.slicePanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1073741823
@@ -165,39 +164,39 @@ entry:
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 2
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
%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) #2
ret { ptr, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(ptr undef) #3
call void @runtime.slicePanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = getelementptr i8, ptr %p, i32 %len
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #2
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) #2
ret ptr %1
}
; Function Attrs: nounwind
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
@@ -206,18 +205,18 @@ slicetoarray.next: ; preds = %entry
ret ptr %s.data
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(ptr undef) #3
call void @runtime.sliceToArrayPointerPanic(ptr undef) #2
unreachable
}
declare void @runtime.sliceToArrayPointerPanic(ptr) #1
declare void @runtime.sliceToArrayPointerPanic(ptr) #0
; Function Attrs: nounwind
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%makeslice = call dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
%makeslice = call ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #2
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
@@ -228,7 +227,7 @@ slicetoarray.throw: ; preds = %entry
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i32 %len, 1073741823
@@ -242,18 +241,18 @@ unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
ret { ptr, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #3
call void @runtime.unsafeSlicePanic(ptr undef) #2
unreachable
}
declare void @runtime.unsafeSlicePanic(ptr) #1
declare void @runtime.unsafeSlicePanic(ptr) #0
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp eq ptr %ptr, null
@@ -266,16 +265,16 @@ unsafe.Slice.next: ; preds = %entry
%4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
ret { ptr, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #3
call void @runtime.unsafeSlicePanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823
@@ -290,16 +289,16 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0
%7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2
ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #3
call void @runtime.unsafeSlicePanic(ptr undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 {
entry:
%stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823
@@ -314,15 +313,14 @@ 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) #2
ret { ptr, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #3
call void @runtime.unsafeSlicePanic(ptr undef) #2
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 }
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
+21 -23
View File
@@ -7,37 +7,36 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 {
entry:
ret %runtime._string { ptr @"main$string", i32 3 }
}
; Function Attrs: nounwind
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 {
entry:
ret %runtime._string zeroinitializer
}
; Function Attrs: nounwind
define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
define hidden i32 @main.stringLen(ptr %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
@@ -48,40 +47,40 @@ lookup.next: ; preds = %entry
ret i8 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #3
call void @runtime.lookupPanic(ptr undef) #2
unreachable
}
declare void @runtime.lookupPanic(ptr) #1
declare void @runtime.lookupPanic(ptr) #0
; Function Attrs: nounwind
define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
define hidden i1 @main.stringCompareEqual(ptr %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
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
ret i1 %0
}
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1
declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #0
; Function Attrs: nounwind
define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
define hidden i1 @main.stringCompareUnequal(ptr %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
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2
%1 = xor i1 %0, true
ret i1 %1
}
; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
define hidden i1 @main.stringCompareLarger(ptr %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
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #2
ret i1 %0
}
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #0
; Function Attrs: nounwind
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
define hidden i8 @main.stringLookup(ptr %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
@@ -93,11 +92,10 @@ lookup.next: ; preds = %entry
ret i8 %2
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #3
call void @runtime.lookupPanic(ptr undef) #2
unreachable
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+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 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
-37
View File
@@ -1,37 +0,0 @@
package main
type hasPadding struct {
b1 bool
i int
b2 bool
}
type nestedPadding struct {
b bool
hasPadding
i int
}
//go:noinline
func testZeroGet(m map[hasPadding]int, s hasPadding) int {
return m[s]
}
//go:noinline
func testZeroSet(m map[hasPadding]int, s hasPadding) {
m[s] = 5
}
//go:noinline
func testZeroArrayGet(m map[[2]hasPadding]int, s [2]hasPadding) int {
return m[s]
}
//go:noinline
func testZeroArraySet(m map[[2]hasPadding]int, s [2]hasPadding) {
m[s] = 5
}
func main() {
}
-140
View File
@@ -1,140 +0,0 @@
; ModuleID = 'zeromap.go'
source_filename = "zeromap.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%main.hasPadding = type { i1, i32, i1 }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #2 {
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 {
entry:
%hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4
%0 = insertvalue %main.hasPadding zeroinitializer, i1 %s.b1, 0
%1 = insertvalue %main.hasPadding %0, i32 %s.i, 1
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 8
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
%5 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
%6 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %6
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4
declare void @runtime.memzero(ptr, i32, ptr) #1
declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4
; 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 {
entry:
%hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4
%0 = insertvalue %main.hasPadding zeroinitializer, i1 %s.b1, 0
%1 = insertvalue %main.hasPadding %0, i32 %s.i, 1
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 8
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void
}
declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1
; 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 {
entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
%5 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %5
}
; 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 {
entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void
}
; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #2 {
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 #5 = { nounwind }
+3 -3
View File
@@ -9,7 +9,7 @@ import "go/types"
// runtime/volatile.LoadT().
func (b *builder) createVolatileLoad() {
b.createFunctionStart(true)
addr := b.getValue(b.fn.Params[0], getPos(b.fn))
addr := b.getValue(b.fn.Params[0])
b.createNilCheck(b.fn.Params[0], addr, "deref")
valType := b.getLLVMType(b.fn.Params[0].Type().(*types.Pointer).Elem())
val := b.CreateLoad(valType, addr, "")
@@ -21,8 +21,8 @@ func (b *builder) createVolatileLoad() {
// runtime/volatile.StoreT().
func (b *builder) createVolatileStore() {
b.createFunctionStart(true)
addr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
addr := b.getValue(b.fn.Params[0])
val := b.getValue(b.fn.Params[1])
b.createNilCheck(b.fn.Params[0], addr, "deref")
store := b.CreateStore(val, addr)
store.SetVolatile(true)
+1 -2
View File
@@ -115,9 +115,8 @@ func TestCorpus(t *testing.T) {
var tags buildutil.TagsFlag
tags.Set(repo.Tags)
opts.Tags = []string(tags)
opts.TestConfig.Verbose = testing.Verbose()
passed, err := Test(path, out, out, &opts, "")
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", false, "")
if err != nil {
t.Errorf("test error: %v", err)
}
+4 -5
View File
@@ -13,12 +13,11 @@ require (
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.8
github.com/mattn/go-tty v0.0.4
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
go.bug.st/serial v1.6.0
golang.org/x/sys v0.11.0
golang.org/x/tools v0.12.0
go.bug.st/serial v1.3.5
golang.org/x/sys v0.4.0
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc
tinygo.org/x/go-llvm v0.0.0-20221028183034-8341240c0b32
)
require (
+9 -11
View File
@@ -43,12 +43,10 @@ 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/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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
go.bug.st/serial v1.3.5 h1:k50SqGZCnHZ2MiBQgzccXWG+kd/XpOs1jUljpDDKzaE=
go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
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=
@@ -56,14 +54,14 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8 h1:LHoToPgySGSr2NcUHbjENAidHz38RkKaNmmntwn9TjI=
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc h1:IVX1dqCX3c88P7iEMBtz1xCAM4UIqCMgbqHdSefBaWE=
tinygo.org/x/go-llvm v0.0.0-20230918183930-9edb6403d0bc/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
tinygo.org/x/go-llvm v0.0.0-20221028183034-8341240c0b32 h1:LvdmoXncO43m2cws1chRB2hkLBAxfN6CbSjDI7+gk4Y=
tinygo.org/x/go-llvm v0.0.0-20221028183034-8341240c0b32/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+99 -53
View File
@@ -4,16 +4,15 @@ package goenv
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"
"sync"
)
// Keys is a slice of all available environment variable keys.
@@ -38,53 +37,6 @@ func init() {
// directory.
var TINYGOROOT string
// Variables read from a `go env` command invocation.
var goEnvVars struct {
GOPATH string
GOROOT string
GOVERSION string
}
var goEnvVarsOnce sync.Once
var goEnvVarsErr error // error returned from cmd.Run
// Make sure goEnvVars is fresh. This can be called multiple times, the first
// time will update all environment variables in goEnvVars.
func readGoEnvVars() error {
goEnvVarsOnce.Do(func() {
cmd := exec.Command("go", "env", "-json", "GOPATH", "GOROOT", "GOVERSION")
output, err := cmd.Output()
if err != nil {
// Check for "command not found" error.
if execErr, ok := err.(*exec.Error); ok {
goEnvVarsErr = fmt.Errorf("could not find '%s' command: %w", execErr.Name, execErr.Err)
return
}
// It's perhaps a bit ugly to handle this error here, but I couldn't
// think of a better place further up in the call chain.
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() != 0 {
if len(exitErr.Stderr) != 0 {
// The 'go' command exited with an error message. Print that
// message and exit, so we behave in a similar way.
os.Stderr.Write(exitErr.Stderr)
os.Exit(exitErr.ExitCode())
}
}
// Other errors. Not sure whether there are any, but just in case.
goEnvVarsErr = err
return
}
err = json.Unmarshal(output, &goEnvVars)
if err != nil {
// This should never happen if we have a sane Go toolchain
// installed.
goEnvVarsErr = fmt.Errorf("unexpected error while unmarshalling `go env` output: %w", err)
}
})
return goEnvVarsErr
}
// Get returns a single environment variable, possibly calculating it on-demand.
// The empty string is returned for unknown environment variables.
func Get(name string) string {
@@ -118,11 +70,15 @@ func Get(name string) string {
// especially when floating point instructions are involved.
return "6"
case "GOROOT":
readGoEnvVars()
return goEnvVars.GOROOT
return getGoroot()
case "GOPATH":
readGoEnvVars()
return goEnvVars.GOPATH
if dir := os.Getenv("GOPATH"); dir != "" {
return dir
}
// fallback
home := getHomeDir()
return filepath.Join(home, "go")
case "GOCACHE":
// Get the cache directory, usually ~/.cache/tinygo
dir, err := os.UserCacheDir()
@@ -284,3 +240,93 @@ func isSourceDir(root string) bool {
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
return err == nil
}
func getHomeDir() string {
u, err := user.Current()
if err != nil {
panic("cannot get current user: " + err.Error())
}
if u.HomeDir == "" {
// This is very unlikely, so panic here.
// Not the nicest solution, however.
panic("could not find home directory")
}
return u.HomeDir
}
// getGoroot returns an appropriate GOROOT from various sources. If it can't be
// found, it returns an empty string.
func getGoroot() string {
// An explicitly set GOROOT always has preference.
goroot := os.Getenv("GOROOT")
if goroot != "" {
// Convert to the standard GOROOT being referenced, if it's a TinyGo cache.
return getStandardGoroot(goroot)
}
// Check for the location of the 'go' binary and base GOROOT on that.
binpath, err := exec.LookPath("go")
if err == nil {
binpath, err = filepath.EvalSymlinks(binpath)
if err == nil {
goroot := filepath.Dir(filepath.Dir(binpath))
if isGoroot(goroot) {
return goroot
}
}
}
// Check what GOROOT was at compile time.
if isGoroot(runtime.GOROOT()) {
return runtime.GOROOT()
}
// Check for some standard locations, as a last resort.
var candidates []string
switch runtime.GOOS {
case "linux":
candidates = []string{
"/usr/local/go", // manually installed
"/usr/lib/go", // from the distribution
"/snap/go/current/", // installed using snap
}
case "darwin":
candidates = []string{
"/usr/local/go", // manually installed
"/usr/local/opt/go/libexec", // from Homebrew
}
}
for _, candidate := range candidates {
if isGoroot(candidate) {
return candidate
}
}
// Can't find GOROOT...
return ""
}
// isGoroot checks whether the given path looks like a GOROOT.
func isGoroot(goroot string) bool {
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
return err == nil
}
// getStandardGoroot returns the physical path to a real, standard Go GOROOT
// implied by the given path.
// If the given path appears to be a TinyGo cached GOROOT, it returns the path
// referenced by symlinks contained in the cache. Otherwise, it returns the
// given path as-is.
func getStandardGoroot(path string) string {
// Check if the "bin" subdirectory of our given GOROOT is a symlink, and then
// return the _parent_ directory of its destination.
if dest, err := os.Readlink(filepath.Join(path, "bin")); nil == err {
// Clean the destination to remove any trailing slashes, so that
// filepath.Dir will always return the parent.
// (because both "/foo" and "/foo/" are valid symlink destinations,
// but filepath.Dir would return "/" and "/foo", respectively)
return filepath.Dir(filepath.Clean(dest))
}
return path
}
+26 -8
View File
@@ -4,12 +4,15 @@ import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
)
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.30.0"
const Version = "0.28.0-dev"
var (
// This variable is set at build time using -ldflags parameters.
@@ -19,8 +22,8 @@ var (
// GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned.
func GetGorootVersion() (major, minor int, err error) {
s, err := GorootVersionString()
func GetGorootVersion(goroot string) (major, minor int, err error) {
s, err := GorootVersionString(goroot)
if err != nil {
return 0, 0, err
}
@@ -48,9 +51,24 @@ func GetGorootVersion() (major, minor int, err error) {
}
// GorootVersionString returns the version string as reported by the Go
// toolchain. It is usually of the form `go1.x.y` but can have some variations
// (for beta releases, for example).
func GorootVersionString() (string, error) {
err := readGoEnvVars()
return goEnvVars.GOVERSION, err
// toolchain for the given GOROOT path. It is usually of the form `go1.x.y` but
// can have some variations (for beta releases, for example).
func GorootVersionString(goroot string) (string, error) {
if data, err := os.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
return string(data), nil
} else if data, err := os.ReadFile(filepath.Join(
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
r := regexp.MustCompile("const version = `(.*)`")
matches := r.FindSubmatch(data)
if len(matches) != 2 {
return "", errors.New("Invalid go version output:\n" + string(data))
}
return string(matches[1]), nil
} else {
return "", err
}
}
+2 -2
View File
@@ -70,7 +70,7 @@ object. Every memory object is given an index, and pointers use that index to
look up the current active object for the pointer to load from or to copy
when storing to it.
Rolling back a function should roll back everything, including the few
Rolling back a function should roll back everyting, including the few
instructions emitted at runtime. This is done by treating instructions much
like memory objects and removing the created instructions when necessary.
@@ -88,7 +88,7 @@ LLVM than initialization code. Also, there are a few other benefits:
they can be propagated and provide some opportunities for other
optimizations (like dead code elimination when branching on the contents of
a global).
* Constants are much more efficient on microcontrollers, as they can be
* Constants are much more efficent on microcontrollers, as they can be
allocated in flash instead of RAM.
The Go SSA package does not create constant initializers for globals.
+2 -5
View File
@@ -49,10 +49,7 @@ func (inst *instruction) String() string {
operands[i] = op.String()
}
name := ""
if int(inst.opcode) < len(instructionNameMap) {
name = instructionNameMap[inst.opcode]
}
name := instructionNameMap[inst.opcode]
if name == "" {
name = "<unknown op>"
}
@@ -257,7 +254,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
}
}
case llvm.BitCast, llvm.IntToPtr, llvm.PtrToInt:
// Bitcasts are usually used to cast a pointer from one type to
// Bitcasts are ususally used to cast a pointer from one type to
// another leaving the pointer itself intact.
inst.name = llvmInst.Name()
inst.operands = []value{
+4 -4
View File
@@ -35,14 +35,14 @@ func isRecoverableError(err error) bool {
// ErrorLine is one line in a traceback. The position may be missing.
type ErrorLine struct {
Pos token.Position
Inst string
Inst llvm.Value
}
// Error encapsulates compile-time interpretation errors with an associated
// import path. The errors may not have a precise location attached.
type Error struct {
ImportPath string
Inst string
Inst llvm.Value
Pos token.Position
Err error
Traceback []ErrorLine
@@ -60,10 +60,10 @@ func (r *runner) errorAt(inst instruction, err error) *Error {
pos := getPosition(inst.llvmInst)
return &Error{
ImportPath: r.pkgName,
Inst: inst.String(),
Inst: inst.llvmInst,
Pos: pos,
Err: err,
Traceback: []ErrorLine{{pos, inst.String()}},
Traceback: []ErrorLine{{pos, inst.llvmInst}},
}
}
+5 -3
View File
@@ -57,14 +57,16 @@ func runTest(t *testing.T, pathPrefix string) {
if err != nil {
if err, match := err.(*Error); match {
println(err.Error())
if len(err.Inst) != 0 {
println(err.Inst)
if !err.Inst.IsNil() {
err.Inst.Dump()
println()
}
if len(err.Traceback) > 0 {
println("\ntraceback:")
for _, line := range err.Traceback {
println(line.Pos.String() + ":")
println(line.Inst)
line.Inst.Dump()
println()
}
}
}
+58 -35
View File
@@ -338,20 +338,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
if mem.hasExternalStore(src) || mem.hasExternalLoadOrStore(dst) {
// These are the same checks as there are on llvm.Load
// and llvm.Store in the interpreter. Copying is
// essentially loading from the source array and storing
// to the destination array, hence why we need to do the
// same checks here.
// This fixes the following bug:
// https://github.com/tinygo-org/tinygo/issues/3890
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
}
continue
}
nBytes := uint32(n * elemSize)
dstObj := mem.getWritable(dst.index())
dstBuf := dstObj.buffer.asRawValue(r)
@@ -360,7 +346,16 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
}
locals[inst.localIndex] = makeLiteralInt(n, inst.llvmInst.Type().IntTypeWidth())
switch inst.llvmInst.Type().IntTypeWidth() {
case 16:
locals[inst.localIndex] = literalValue{uint16(n)}
case 32:
locals[inst.localIndex] = literalValue{uint32(n)}
case 64:
locals[inst.localIndex] = literalValue{uint64(n)}
default:
panic("unknown integer type width")
}
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
// Copy a block of memory from one pointer to another.
dst, err := operands[1].asPointer(r)
@@ -543,7 +538,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// how this function got called.
callErr.Traceback = append(callErr.Traceback, ErrorLine{
Pos: getPosition(inst.llvmInst),
Inst: inst.String(),
Inst: inst.llvmInst,
})
return nil, mem, callErr
}
@@ -652,7 +647,16 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// GEP on fixed pointer value (for example, memory-mapped I/O).
ptrValue := operands[0].Uint() + offset
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
switch operands[0].len(r) {
case 8:
locals[inst.localIndex] = literalValue{uint64(ptrValue)}
case 4:
locals[inst.localIndex] = literalValue{uint32(ptrValue)}
case 2:
locals[inst.localIndex] = literalValue{uint16(ptrValue)}
default:
panic("pointer operand is not of a known pointer size")
}
continue
}
ptr = ptr.addOffset(int64(offset))
@@ -750,33 +754,30 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err == nil {
// The lhs is a pointer. This sometimes happens for particular
// pointer tricks.
if inst.opcode == llvm.Add {
switch inst.opcode {
case llvm.Add:
// This likely means this is part of a
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
locals[inst.localIndex] = lhsPtr
} 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() < 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()
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
} else {
continue
case llvm.Xor:
if 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
continue
}
default:
// Catch-all for weird operations that should just be done
// at runtime.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
}
continue
}
continue
}
var result uint64
switch inst.opcode {
@@ -809,7 +810,18 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
default:
panic("unreachable")
}
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
switch lhs.len(r) {
case 8:
locals[inst.localIndex] = literalValue{result}
case 4:
locals[inst.localIndex] = literalValue{uint32(result)}
case 2:
locals[inst.localIndex] = literalValue{uint16(result)}
case 1:
locals[inst.localIndex] = literalValue{uint8(result)}
default:
panic("unknown integer size")
}
if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", lhs, rhs, "->", result)
}
@@ -831,7 +843,18 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
}
locals[inst.localIndex] = makeLiteralInt(value, int(bitwidth))
switch bitwidth {
case 64:
locals[inst.localIndex] = literalValue{value}
case 32:
locals[inst.localIndex] = literalValue{uint32(value)}
case 16:
locals[inst.localIndex] = literalValue{uint16(value)}
case 8:
locals[inst.localIndex] = literalValue{uint8(value)}
default:
panic("unknown integer size in sext/zext/trunc")
}
case llvm.SIToFP, llvm.UIToFP:
var value float64
switch inst.opcode {
+1 -17
View File
@@ -12,7 +12,7 @@ package interp
// done in interp and results in a revert.
//
// Right now the memory is assumed to be little endian. This will need an update
// for big endian architectures, if TinyGo ever adds support for one.
// for big endian arcitectures, if TinyGo ever adds support for one.
import (
"encoding/binary"
@@ -373,22 +373,6 @@ type literalValue struct {
value interface{}
}
// Make a literalValue given the number of bits.
func makeLiteralInt(value uint64, bits int) literalValue {
switch bits {
case 64:
return literalValue{value}
case 32:
return literalValue{uint32(value)}
case 16:
return literalValue{uint16(value)}
case 8:
return literalValue{uint8(value)}
default:
panic("unknown integer size")
}
}
func (v literalValue) len(r *runner) uint32 {
switch v.value.(type) {
case uint64:
+28 -28
View File
@@ -2,17 +2,17 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32--wasi"
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@pointerFree12 = global ptr null
@pointerFree7 = global ptr null
@pointerFree3 = global ptr null
@pointerFree0 = global ptr null
@layout1 = global ptr null
@layout2 = global ptr null
@layout3 = global ptr null
@layout4 = global ptr null
@bigobj1 = global ptr null
@pointerFree12 = global i8* null
@pointerFree7 = global i8* null
@pointerFree3 = global i8* null
@pointerFree0 = global i8* null
@layout1 = global i8* null
@layout2 = global i8* null
@layout3 = global i8* null
@layout4 = global i8* null
@bigobj1 = global i8* null
declare ptr @runtime.alloc(i32, ptr) unnamed_addr
declare i8* @runtime.alloc(i32, i8*) unnamed_addr
define void @runtime.initAll() unnamed_addr {
call void @main.init()
@@ -21,33 +21,33 @@ define void @runtime.initAll() unnamed_addr {
define internal void @main.init() unnamed_addr {
; Object that's word-aligned.
%pointerFree12 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 3 to ptr))
store ptr %pointerFree12, ptr @pointerFree12
%pointerFree12 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 3 to i8*))
store i8* %pointerFree12, i8** @pointerFree12
; Object larger than a word but not word-aligned.
%pointerFree7 = call ptr @runtime.alloc(i32 7, ptr inttoptr (i32 3 to ptr))
store ptr %pointerFree7, ptr @pointerFree7
%pointerFree7 = call i8* @runtime.alloc(i32 7, i8* inttoptr (i32 3 to i8*))
store i8* %pointerFree7, i8** @pointerFree7
; Object smaller than a word (and of course not word-aligned).
%pointerFree3 = call ptr @runtime.alloc(i32 3, ptr inttoptr (i32 3 to ptr))
store ptr %pointerFree3, ptr @pointerFree3
%pointerFree3 = call i8* @runtime.alloc(i32 3, i8* inttoptr (i32 3 to i8*))
store i8* %pointerFree3, i8** @pointerFree3
; Zero-sized object.
%pointerFree0 = call ptr @runtime.alloc(i32 0, ptr inttoptr (i32 3 to ptr))
store ptr %pointerFree0, ptr @pointerFree0
%pointerFree0 = call i8* @runtime.alloc(i32 0, i8* inttoptr (i32 3 to i8*))
store i8* %pointerFree0, i8** @pointerFree0
; Object made out of 3 pointers.
%layout1 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 67 to ptr))
store ptr %layout1, ptr @layout1
%layout1 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 67 to i8*))
store i8* %layout1, i8** @layout1
; Array (or slice) of 5 slices.
%layout2 = call ptr @runtime.alloc(i32 60, ptr inttoptr (i32 71 to ptr))
store ptr %layout2, ptr @layout2
%layout2 = call i8* @runtime.alloc(i32 60, i8* inttoptr (i32 71 to i8*))
store i8* %layout2, i8** @layout2
; Oddly shaped object, using all bits in the layout integer.
%layout3 = call ptr @runtime.alloc(i32 104, ptr inttoptr (i32 2467830261 to ptr))
store ptr %layout3, ptr @layout3
%layout3 = call i8* @runtime.alloc(i32 104, i8* inttoptr (i32 2467830261 to i8*))
store i8* %layout3, i8** @layout3
; ...repeated.
%layout4 = call ptr @runtime.alloc(i32 312, ptr inttoptr (i32 2467830261 to ptr))
store ptr %layout4, ptr @layout4
%layout4 = call i8* @runtime.alloc(i32 312, i8* inttoptr (i32 2467830261 to i8*))
store i8* %layout4, i8** @layout4
; Large object that needs to be stored in a separate global.
%bigobj1 = call ptr @runtime.alloc(i32 248, ptr @"runtime/gc.layout:62-2000000000000001")
store ptr %bigobj1, ptr @bigobj1
%bigobj1 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*))
store i8* %bigobj1, i8** @bigobj1
ret void
}
+14 -14
View File
@@ -1,24 +1,24 @@
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32--wasi"
@pointerFree12 = local_unnamed_addr global ptr @"main$alloc"
@pointerFree7 = local_unnamed_addr global ptr @"main$alloc.1"
@pointerFree3 = local_unnamed_addr global ptr @"main$alloc.2"
@pointerFree0 = local_unnamed_addr global ptr @"main$alloc.3"
@layout1 = local_unnamed_addr global ptr @"main$alloc.4"
@layout2 = local_unnamed_addr global ptr @"main$alloc.5"
@layout3 = local_unnamed_addr global ptr @"main$alloc.6"
@layout4 = local_unnamed_addr global ptr @"main$alloc.7"
@bigobj1 = local_unnamed_addr global ptr @"main$alloc.8"
@pointerFree12 = local_unnamed_addr global i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"main$alloc", i32 0, i32 0)
@pointerFree7 = local_unnamed_addr global i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"main$alloc.1", i32 0, i32 0)
@pointerFree3 = local_unnamed_addr global i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$alloc.2", i32 0, i32 0)
@pointerFree0 = local_unnamed_addr global i8* getelementptr inbounds ([0 x i8], [0 x i8]* @"main$alloc.3", i32 0, i32 0)
@layout1 = local_unnamed_addr global i8* bitcast ([3 x i8*]* @"main$alloc.4" to i8*)
@layout2 = local_unnamed_addr global i8* bitcast ([5 x { i8*, i32, i32 }]* @"main$alloc.5" to i8*)
@layout3 = local_unnamed_addr global i8* bitcast ({ i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }* @"main$alloc.6" to i8*)
@layout4 = local_unnamed_addr global i8* bitcast ([3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }]* @"main$alloc.7" to i8*)
@bigobj1 = local_unnamed_addr global i8* bitcast ({ i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* }* @"main$alloc.8" to i8*)
@"main$alloc" = internal global [12 x i8] zeroinitializer, align 4
@"main$alloc.1" = internal global [7 x i8] zeroinitializer, align 4
@"main$alloc.2" = internal global [3 x i8] zeroinitializer, align 4
@"main$alloc.3" = internal global [0 x i8] zeroinitializer, align 4
@"main$alloc.4" = internal global [3 x ptr] zeroinitializer, align 4
@"main$alloc.5" = internal global [5 x { ptr, i32, i32 }] zeroinitializer, align 4
@"main$alloc.6" = internal global { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr } zeroinitializer, align 4
@"main$alloc.7" = internal global [3 x { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr }] zeroinitializer, align 4
@"main$alloc.8" = internal global { ptr, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, ptr } zeroinitializer, align 4
@"main$alloc.4" = internal global [3 x i8*] zeroinitializer, align 4
@"main$alloc.5" = internal global [5 x { i8*, i32, i32 }] zeroinitializer, align 4
@"main$alloc.6" = internal global { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* } zeroinitializer, align 4
@"main$alloc.7" = internal global [3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }] zeroinitializer, align 4
@"main$alloc.8" = internal global { i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* } zeroinitializer, align 4
define void @runtime.initAll() unnamed_addr {
ret void
+21 -21
View File
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
@main.nonConst1 = global [4 x i64] zeroinitializer
@main.nonConst2 = global i64 0
@main.someArray = global [8 x {i16, i32}] zeroinitializer
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
@main.exportedConst = constant i64 42
@main.exposedValue1 = global i16 0
@main.exposedValue2 = global i16 0
@@ -24,7 +24,7 @@ entry:
define void @main() unnamed_addr {
entry:
%0 = load i64, ptr @main.v1
%0 = load i64, i64* @main.v1
call void @runtime.printint64(i64 %0)
call void @runtime.printnl()
ret void
@@ -37,43 +37,43 @@ entry:
define internal void @main.init() unnamed_addr {
entry:
store i64 3, ptr @main.v1
store i64 3, i64* @main.v1
call void @"main.init#1"()
; test the following pattern:
; func someValue() int // extern function
; var nonConst1 = [4]int{someValue(), 0, 0, 0}
%value1 = call i64 @someValue()
%gep1 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
store i64 %value1, ptr %gep1
%gep1 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
store i64 %value1, i64* %gep1
; Test that the global really is marked dirty:
; var nonConst2 = nonConst1[0]
%gep2 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
%value2 = load i64, ptr %gep2
store i64 %value2, ptr @main.nonConst2
%gep2 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
%value2 = load i64, i64* %gep2
store i64 %value2, i64* @main.nonConst2
; Test that the following GEP works:
; var someArray
; modifyExternal(&someArray[3].field1)
%gep3 = getelementptr [8 x {i16, i32}], ptr @main.someArray, i32 0, i32 3, i32 1
call void @modifyExternal(ptr %gep3)
%gep3 = getelementptr [8 x {i16, i32}], [8 x {i16, i32}]* @main.someArray, i32 0, i32 3, i32 1
call void @modifyExternal(i32* %gep3)
; Test that marking a value as external also marks all referenced values.
call void @modifyExternal(ptr @main.exportedValue)
store i16 5, ptr @main.exposedValue1
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
store i16 5, i16* @main.exposedValue1
; Test that marking a constant as external still allows loading from it.
call void @readExternal(ptr @main.exportedConst)
%constLoad = load i64, ptr @main.exportedConst
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
%constLoad = load i64, i64 * @main.exportedConst
call void @runtime.printint64(i64 %constLoad)
; Test that this even propagates through functions.
call void @modifyExternal(ptr @willModifyGlobal)
store i16 7, ptr @main.exposedValue2
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
store i16 7, i16* @main.exposedValue2
; Test that inline assembly is ignored.
call void @modifyExternal(ptr @hasInlineAsm)
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
; Test switch statement.
%switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6
@@ -86,7 +86,7 @@ entry:
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
call void @runtime.printint64(i64 %elt)
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
ret void
}
@@ -100,16 +100,16 @@ entry:
declare i64 @someValue()
declare void @modifyExternal(ptr)
declare void @modifyExternal(i32*)
declare void @readExternal(ptr)
declare void @readExternal(i32*)
; This function will modify an external value. By passing this function as a
; function pointer to an external function, @main.exposedValue2 should be
; marked as external.
define void @willModifyGlobal() {
entry:
store i16 8, ptr @main.exposedValue2
store i16 8, i16* @main.exposedValue2
ret void
}
+15 -15
View File
@@ -4,7 +4,7 @@ target triple = "x86_64--linux"
@main.nonConst1 = local_unnamed_addr global [4 x i64] zeroinitializer
@main.nonConst2 = local_unnamed_addr global i64 0
@main.someArray = global [8 x { i16, i32 }] zeroinitializer
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
@main.exportedConst = constant i64 42
@main.exposedValue1 = global i16 0
@main.exposedValue2 = local_unnamed_addr global i16 0
@@ -19,17 +19,17 @@ entry:
call void @runtime.printint64(i64 5)
call void @runtime.printnl()
%value1 = call i64 @someValue()
store i64 %value1, ptr @main.nonConst1, align 8
%value2 = load i64, ptr @main.nonConst1, align 8
store i64 %value2, ptr @main.nonConst2, align 8
call void @modifyExternal(ptr getelementptr inbounds (i8, ptr @main.someArray, i32 28))
call void @modifyExternal(ptr @main.exportedValue)
store i16 5, ptr @main.exposedValue1, align 2
call void @readExternal(ptr @main.exportedConst)
store i64 %value1, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
%value2 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
store i64 %value2, i64* @main.nonConst2, align 8
call void @modifyExternal(i32* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ([8 x { i16, i32 }]* @main.someArray to i8*), i32 28) to i32*))
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
store i16 5, i16* @main.exposedValue1, align 2
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
call void @runtime.printint64(i64 42)
call void @modifyExternal(ptr @willModifyGlobal)
store i16 7, ptr @main.exposedValue2, align 2
call void @modifyExternal(ptr @hasInlineAsm)
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
store i16 7, i16* @main.exposedValue2, align 2
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
call void @runtime.printint64(i64 6)
call void @runtime.printint64(i64 -1)
%agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct()
@@ -42,7 +42,7 @@ entry:
%agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0
%agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1
%agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, ptr @main.insertedValue, align 8
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue, align 8
ret void
}
@@ -55,13 +55,13 @@ entry:
declare i64 @someValue() local_unnamed_addr
declare void @modifyExternal(ptr) local_unnamed_addr
declare void @modifyExternal(i32*) local_unnamed_addr
declare void @readExternal(ptr) local_unnamed_addr
declare void @readExternal(i32*) local_unnamed_addr
define void @willModifyGlobal() {
entry:
store i16 8, ptr @main.exposedValue2, align 2
store i16 8, i16* @main.exposedValue2, align 2
ret void
}
+11 -19
View File
@@ -4,9 +4,8 @@ target triple = "x86_64--linux"
@intToPtrResult = global i8 0
@ptrToIntResult = global i8 0
@icmpResult = global i8 0
@pointerTagResult = global i64 0
@someArray = internal global {i16, i8, i8} zeroinitializer
@someArrayPointer = global ptr zeroinitializer
@someArrayPointer = global i8* zeroinitializer
define void @runtime.initAll() {
call void @main.init()
@@ -18,56 +17,49 @@ define internal void @main.init() {
call void @testPtrToInt()
call void @testConstGEP()
call void @testICmp()
call void @testPointerTag()
ret void
}
define internal void @testIntToPtr() {
%nil = icmp eq ptr inttoptr (i64 1024 to ptr), null
%nil = icmp eq i8* inttoptr (i64 1024 to i8*), null
br i1 %nil, label %a, label %b
a:
; should not be reached
store i8 1, ptr @intToPtrResult
store i8 1, i8* @intToPtrResult
ret void
b:
; should be reached
store i8 2, ptr @intToPtrResult
store i8 2, i8* @intToPtrResult
ret void
}
define internal void @testPtrToInt() {
%zero = icmp eq i64 ptrtoint (ptr @ptrToIntResult to i64), 0
%zero = icmp eq i64 ptrtoint (i8* @ptrToIntResult to i64), 0
br i1 %zero, label %a, label %b
a:
; should not be reached
store i8 1, ptr @ptrToIntResult
store i8 1, i8* @ptrToIntResult
ret void
b:
; should be reached
store i8 2, ptr @ptrToIntResult
store i8 2, i8* @ptrToIntResult
ret void
}
define internal void @testConstGEP() {
store ptr getelementptr inbounds (i8, ptr @someArray, i32 2), ptr @someArrayPointer
store i8* getelementptr inbounds (i8, i8* bitcast ({i16, i8, i8}* @someArray to i8*), i32 2), i8** @someArrayPointer
ret void
}
define internal void @testICmp() {
br i1 icmp eq (i64 ptrtoint (ptr @ptrToIntResult to i64), i64 0), label %equal, label %unequal
br i1 icmp eq (i64 ptrtoint (i8* @ptrToIntResult to i64), i64 0), label %equal, label %unequal
equal:
; should not be reached
store i8 1, ptr @icmpResult
store i8 1, i8* @icmpResult
ret void
unequal:
; should be reached
store i8 2, ptr @icmpResult
store i8 2, i8* @icmpResult
ret void
ret void
}
define internal void @testPointerTag() {
%val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3
store i64 %val, ptr @pointerTagResult
ret void
}
+1 -2
View File
@@ -4,9 +4,8 @@ target triple = "x86_64--linux"
@intToPtrResult = local_unnamed_addr global i8 2
@ptrToIntResult = local_unnamed_addr global i8 2
@icmpResult = local_unnamed_addr global i8 2
@pointerTagResult = local_unnamed_addr global i64 2
@someArray = internal global { i16, i8, i8 } zeroinitializer
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds ({ i16, i8, i8 }, ptr @someArray, i64 0, i32 1)
@someArrayPointer = local_unnamed_addr global i8* getelementptr inbounds ({ i16, i8, i8 }, { i16, i8, i8 }* @someArray, i64 0, i32 1)
define void @runtime.initAll() local_unnamed_addr {
ret void
+9 -9
View File
@@ -3,14 +3,14 @@ target triple = "x86_64--linux"
@main.v1 = global i1 0
@main.v2 = global i1 0
@"reflect/types.type:named:main.foo" = private constant { i8, ptr, ptr } { i8 34, ptr @"reflect/types.type:pointer:named:main.foo", ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, ptr }
@"reflect/types.type:named:main.foo" = private constant { i8, i8*, i8* } { i8 34, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:named:main.foo", i32 0, i32 0), i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:basic:int", i32 0, i32 0) }, align 4
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, i8* }
@"reflect/types.typeid:named:main.foo" = external constant i8
@"reflect/types.type:basic:int" = private constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = external constant { i8, ptr }
@"reflect/types.type:basic:int" = private constant { i8, i8* } { i8 2, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:basic:int", i32 0, i32 0) }, align 4
@"reflect/types.type:pointer:basic:int" = external constant { i8, i8* }
declare i1 @runtime.typeAssert(ptr, ptr, ptr, ptr)
declare i1 @runtime.typeAssert(i8*, i8*, i8*, i8*)
define void @runtime.initAll() unnamed_addr {
entry:
@@ -21,9 +21,9 @@ entry:
define internal void @main.init() unnamed_addr {
entry:
; Test type asserts.
%typecode = call i1 @runtime.typeAssert(ptr @"reflect/types.type:named:main.foo", ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
store i1 %typecode, ptr @main.v1
%typecode2 = call i1 @runtime.typeAssert(ptr null, ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
store i1 %typecode2, ptr @main.v2
%typecode = call i1 @runtime.typeAssert(i8* getelementptr inbounds ({ i8, i8*, i8* }, { i8, i8*, i8* }* @"reflect/types.type:named:main.foo", i32 0, i32 0), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
%typecode2 = call i1 @runtime.typeAssert(i8* null, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode2, i1* @main.v2
ret void
}
+2 -2
View File
@@ -25,7 +25,7 @@ for.loop:
br i1 %icmp, label %for.done, label %for.loop
for.done:
store i8 %a, ptr @main.phiNodesResultA
store i8 %b, ptr @main.phiNodesResultB
store i8 %a, i8* @main.phiNodesResultA
store i8 %b, i8* @main.phiNodesResultB
ret void
}
+37 -34
View File
@@ -3,7 +3,7 @@ target triple = "x86_64--linux"
declare void @externalCall(i64)
declare i64 @ptrHash(ptr nocapture)
declare i64 @ptrHash(i8* nocapture)
@foo.knownAtRuntime = global i64 0
@bar.knownAtRuntime = global i64 0
@@ -17,60 +17,60 @@ declare i64 @ptrHash(ptr nocapture)
define void @runtime.initAll() unnamed_addr {
entry:
call void @baz.init(ptr undef)
call void @foo.init(ptr undef)
call void @bar.init(ptr undef)
call void @main.init(ptr undef)
call void @x.init(ptr undef)
call void @y.init(ptr undef)
call void @z.init(ptr undef)
call void @baz.init(i8* undef)
call void @foo.init(i8* undef)
call void @bar.init(i8* undef)
call void @main.init(i8* undef)
call void @x.init(i8* undef)
call void @y.init(i8* undef)
call void @z.init(i8* undef)
ret void
}
define internal void @foo.init(ptr %context) unnamed_addr {
store i64 5, ptr @foo.knownAtRuntime
define internal void @foo.init(i8* %context) unnamed_addr {
store i64 5, i64* @foo.knownAtRuntime
unreachable ; this triggers a revert of @foo.init.
}
define internal void @bar.init(ptr %context) unnamed_addr {
%val = load i64, ptr @foo.knownAtRuntime
store i64 %val, ptr @bar.knownAtRuntime
define internal void @bar.init(i8* %context) unnamed_addr {
%val = load i64, i64* @foo.knownAtRuntime
store i64 %val, i64* @bar.knownAtRuntime
ret void
}
define internal void @baz.init(ptr %context) unnamed_addr {
define internal void @baz.init(i8* %context) unnamed_addr {
; Test extractvalue/insertvalue with more than one index.
%val = load [3 x {i64, i32}], ptr @baz.someGlobal
%val = load [3 x {i64, i32}], [3 x {i64, i32}]* @baz.someGlobal
%part = extractvalue [3 x {i64, i32}] %val, 0, 1
%val2 = insertvalue [3 x {i64, i32}] %val, i32 5, 2, 1
unreachable ; trigger revert
}
define internal void @main.init(ptr %context) unnamed_addr {
define internal void @main.init(i8* %context) unnamed_addr {
entry:
call void @externalCall(i64 3)
ret void
}
define internal void @x.init(ptr %context) unnamed_addr {
define internal void @x.init(i8* %context) unnamed_addr {
; Test atomic and volatile memory accesses.
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
store i32 %x, ptr @x.atomicNum
%y = load volatile i32, ptr @x.volatileNum
store volatile i32 %y, ptr @x.volatileNum
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
store i32 %x, i32* @x.atomicNum
%y = load volatile i32, i32* @x.volatileNum
store volatile i32 %y, i32* @x.volatileNum
ret void
}
define internal void @y.init(ptr %context) unnamed_addr {
define internal void @y.init(i8* %context) unnamed_addr {
entry:
br label %loop
loop:
; Test a wait-loop.
; This function must be reverted.
%val = load atomic i32, ptr @y.ready seq_cst, align 4
%val = load atomic i32, i32* @y.ready seq_cst, align 4
%ready = icmp eq i32 %val, 1
br i1 %ready, label %end, label %loop
@@ -78,25 +78,27 @@ end:
ret void
}
define internal void @z.init(ptr %context) unnamed_addr {
define internal void @z.init(i8* %context) unnamed_addr {
%bloom = bitcast i64* @z.bloom to i8*
; This can be safely expanded.
call void @z.setArr(ptr @z.bloom, i64 1, ptr @z.bloom)
call void @z.setArr(i8* %bloom, i64 1, i8* %bloom)
; This call should be reverted to prevent unrolling.
call void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
call void @z.setArr(i8* bitcast ([32 x i8]* @z.arr to i8*), i64 32, i8* %bloom)
ret void
}
define internal void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
define internal void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
entry:
br label %loop
loop:
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
%idx = sub i64 %prev, 1
%elem = getelementptr i8, ptr %arr, i64 %idx
call void @z.set(ptr %elem, ptr %context)
%elem = getelementptr i8, i8* %arr, i64 %idx
call void @z.set(i8* %elem, i8* %context)
%done = icmp eq i64 %idx, 0
br i1 %done, label %end, label %loop
@@ -104,13 +106,14 @@ end:
ret void
}
define internal void @z.set(ptr %ptr, ptr %context) unnamed_addr {
define internal void @z.set(i8* %ptr, i8* %context) unnamed_addr {
; Insert the pointer into the Bloom filter.
%hash = call i64 @ptrHash(ptr %ptr)
%hash = call i64 @ptrHash(i8* %ptr)
%index = lshr i64 %hash, 58
%bit = shl i64 1, %index
%old = load i64, ptr %context
%bloom = bitcast i8* %context to i64*
%old = load i64, i64* %bloom
%new = or i64 %old, %bit
store i64 %new, ptr %context
store i64 %new, i64* %bloom
ret void
}
+28 -27
View File
@@ -13,41 +13,41 @@ target triple = "x86_64--linux"
declare void @externalCall(i64) local_unnamed_addr
declare i64 @ptrHash(ptr nocapture) local_unnamed_addr
declare i64 @ptrHash(i8* nocapture) local_unnamed_addr
define void @runtime.initAll() unnamed_addr {
entry:
call fastcc void @baz.init(ptr undef)
call fastcc void @foo.init(ptr undef)
%val = load i64, ptr @foo.knownAtRuntime, align 8
store i64 %val, ptr @bar.knownAtRuntime, align 8
call fastcc void @baz.init(i8* undef)
call fastcc void @foo.init(i8* undef)
%val = load i64, i64* @foo.knownAtRuntime, align 8
store i64 %val, i64* @bar.knownAtRuntime, align 8
call void @externalCall(i64 3)
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
store i32 %x, ptr @x.atomicNum, align 4
%y = load volatile i32, ptr @x.volatileNum, align 4
store volatile i32 %y, ptr @x.volatileNum, align 4
call fastcc void @y.init(ptr undef)
call fastcc void @z.set(ptr @z.bloom, ptr @z.bloom)
call fastcc void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
store i32 %x, i32* @x.atomicNum, align 4
%y = load volatile i32, i32* @x.volatileNum, align 4
store volatile i32 %y, i32* @x.volatileNum, align 4
call fastcc void @y.init(i8* undef)
call fastcc void @z.set(i8* bitcast (i64* @z.bloom to i8*), i8* bitcast (i64* @z.bloom to i8*))
call fastcc void @z.setArr(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @z.arr, i32 0, i32 0), i64 32, i8* bitcast (i64* @z.bloom to i8*))
ret void
}
define internal fastcc void @foo.init(ptr %context) unnamed_addr {
store i64 5, ptr @foo.knownAtRuntime, align 8
define internal fastcc void @foo.init(i8* %context) unnamed_addr {
store i64 5, i64* @foo.knownAtRuntime, align 8
unreachable
}
define internal fastcc void @baz.init(ptr %context) unnamed_addr {
define internal fastcc void @baz.init(i8* %context) unnamed_addr {
unreachable
}
define internal fastcc void @y.init(ptr %context) unnamed_addr {
define internal fastcc void @y.init(i8* %context) unnamed_addr {
entry:
br label %loop
loop: ; preds = %loop, %entry
%val = load atomic i32, ptr @y.ready seq_cst, align 4
%val = load atomic i32, i32* @y.ready seq_cst, align 4
%ready = icmp eq i32 %val, 1
br i1 %ready, label %end, label %loop
@@ -55,15 +55,15 @@ end: ; preds = %loop
ret void
}
define internal fastcc void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
define internal fastcc void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
entry:
br label %loop
loop: ; preds = %loop, %entry
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
%idx = sub i64 %prev, 1
%elem = getelementptr i8, ptr %arr, i64 %idx
call fastcc void @z.set(ptr %elem, ptr %context)
%elem = getelementptr i8, i8* %arr, i64 %idx
call fastcc void @z.set(i8* %elem, i8* %context)
%done = icmp eq i64 %idx, 0
br i1 %done, label %end, label %loop
@@ -71,12 +71,13 @@ end: ; preds = %loop
ret void
}
define internal fastcc void @z.set(ptr %ptr, ptr %context) unnamed_addr {
%hash = call i64 @ptrHash(ptr %ptr)
define internal fastcc void @z.set(i8* %ptr, i8* %context) unnamed_addr {
%hash = call i64 @ptrHash(i8* %ptr)
%index = lshr i64 %hash, 58
%bit = shl i64 1, %index
%old = load i64, ptr %context, align 8
%bloom = bitcast i8* %context to i64*
%old = load i64, i64* %bloom, align 8
%new = or i64 %old, %bit
store i64 %new, ptr %context, align 8
store i64 %new, i64* %bloom, align 8
ret void
}
}
+35 -55
View File
@@ -2,26 +2,20 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.uint8SliceSrc.buf = internal global [2 x i8] c"\03d"
@main.uint8SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.uint8SliceSrc.buf, i64 2, i64 2 }
@main.uint8SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
@main.uint8SliceSrc = internal unnamed_addr global { i8*, i64, i64 } { i8* getelementptr inbounds ([2 x i8], [2 x i8]* @main.uint8SliceSrc.buf, i32 0, i32 0), i64 2, i64 2 }
@main.uint8SliceDst = internal unnamed_addr global { i8*, i64, i64 } zeroinitializer
@main.int16SliceSrc.buf = internal global [3 x i16] [i16 5, i16 123, i16 1024]
@main.int16SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.int16SliceSrc.buf, i64 3, i64 3 }
@main.int16SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
@main.sliceSrcUntaint.buf = internal global [2 x i8] c"ab"
@main.sliceDstUntaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
@main.int16SliceSrc = internal unnamed_addr global { i16*, i64, i64 } { i16* getelementptr inbounds ([3 x i16], [3 x i16]* @main.int16SliceSrc.buf, i32 0, i32 0), i64 3, i64 3 }
@main.int16SliceDst = internal unnamed_addr global { i16*, i64, i64 } zeroinitializer
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
declare i64 @runtime.sliceCopy(i8* %dst, i8* %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
declare ptr @runtime.alloc(i64, ptr) unnamed_addr
declare i8* @runtime.alloc(i64, i8*) unnamed_addr
declare void @runtime.printuint8(i8)
declare void @runtime.printint16(i16)
declare void @use(ptr)
define void @runtime.initAll() unnamed_addr {
entry:
call void @main.init()
@@ -31,33 +25,24 @@ entry:
define void @main() unnamed_addr {
entry:
; print(uintSliceSrc[0])
%uint8SliceSrc.buf = load ptr, ptr @main.uint8SliceSrc
%uint8SliceSrc.val = load i8, ptr %uint8SliceSrc.buf
%uint8SliceSrc.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc, i64 0, i32 0)
%uint8SliceSrc.val = load i8, i8* %uint8SliceSrc.buf
call void @runtime.printuint8(i8 %uint8SliceSrc.val)
; print(uintSliceDst[0])
%uint8SliceDst.buf = load ptr, ptr @main.uint8SliceDst
%uint8SliceDst.val = load i8, ptr %uint8SliceDst.buf
%uint8SliceDst.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceDst, i64 0, i32 0)
%uint8SliceDst.val = load i8, i8* %uint8SliceDst.buf
call void @runtime.printuint8(i8 %uint8SliceDst.val)
; print(int16SliceSrc[0])
%int16SliceSrc.buf = load ptr, ptr @main.int16SliceSrc
%int16SliceSrc.val = load i16, ptr %int16SliceSrc.buf
%int16SliceSrc.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc, i64 0, i32 0)
%int16SliceSrc.val = load i16, i16* %int16SliceSrc.buf
call void @runtime.printint16(i16 %int16SliceSrc.val)
; print(int16SliceDst[0])
%int16SliceDst.buf = load ptr, ptr @main.int16SliceDst
%int16SliceDst.val = load i16, ptr %int16SliceDst.buf
%int16SliceDst.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceDst, i64 0, i32 0)
%int16SliceDst.val = load i16, i16* %int16SliceDst.buf
call void @runtime.printint16(i16 %int16SliceDst.val)
; print(sliceDstUntaint[0])
%sliceDstUntaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstUntaint.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstUntaint.val)
; print(sliceDstTaint[0])
%sliceDstTaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstTaint.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstTaint.val)
ret void
}
@@ -65,42 +50,37 @@ define internal void @main.init() unnamed_addr {
entry:
; equivalent of:
; uint8SliceDst = make([]uint8, len(uint8SliceSrc))
%uint8SliceSrc = load { ptr, i64, i64 }, ptr @main.uint8SliceSrc
%uint8SliceSrc.len = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 1
%uint8SliceDst.buf = call ptr @runtime.alloc(i64 %uint8SliceSrc.len, ptr null)
%0 = insertvalue { ptr, i64, i64 } undef, ptr %uint8SliceDst.buf, 0
%1 = insertvalue { ptr, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
%2 = insertvalue { ptr, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
store { ptr, i64, i64 } %2, ptr @main.uint8SliceDst
%uint8SliceSrc = load { i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc
%uint8SliceSrc.len = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 1
%uint8SliceDst.buf = call i8* @runtime.alloc(i64 %uint8SliceSrc.len, i8* null)
%0 = insertvalue { i8*, i64, i64 } undef, i8* %uint8SliceDst.buf, 0
%1 = insertvalue { i8*, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
%2 = insertvalue { i8*, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
store { i8*, i64, i64 } %2, { i8*, i64, i64 }* @main.uint8SliceDst
; equivalent of:
; copy(uint8SliceDst, uint8SliceSrc)
%uint8SliceSrc.buf = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 0
%copy.n = call i64 @runtime.sliceCopy(ptr %uint8SliceDst.buf, ptr %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
%uint8SliceSrc.buf = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 0
%copy.n = call i64 @runtime.sliceCopy(i8* %uint8SliceDst.buf, i8* %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
; equivalent of:
; int16SliceDst = make([]int16, len(int16SliceSrc))
%int16SliceSrc = load { ptr, i64, i64 }, ptr @main.int16SliceSrc
%int16SliceSrc.len = extractvalue { ptr, i64, i64 } %int16SliceSrc, 1
%int16SliceSrc = load { i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc
%int16SliceSrc.len = extractvalue { i16*, i64, i64 } %int16SliceSrc, 1
%int16SliceSrc.len.bytes = mul i64 %int16SliceSrc.len, 2
%int16SliceDst.buf = call ptr @runtime.alloc(i64 %int16SliceSrc.len.bytes, ptr null)
%3 = insertvalue { ptr, i64, i64 } undef, ptr %int16SliceDst.buf, 0
%4 = insertvalue { ptr, i64, i64 } %3, i64 %int16SliceSrc.len, 1
%5 = insertvalue { ptr, i64, i64 } %4, i64 %int16SliceSrc.len, 2
store { ptr, i64, i64 } %5, ptr @main.int16SliceDst
%int16SliceDst.buf.raw = call i8* @runtime.alloc(i64 %int16SliceSrc.len.bytes, i8* null)
%int16SliceDst.buf = bitcast i8* %int16SliceDst.buf.raw to i16*
%3 = insertvalue { i16*, i64, i64 } undef, i16* %int16SliceDst.buf, 0
%4 = insertvalue { i16*, i64, i64 } %3, i64 %int16SliceSrc.len, 1
%5 = insertvalue { i16*, i64, i64 } %4, i64 %int16SliceSrc.len, 2
store { i16*, i64, i64 } %5, { i16*, i64, i64 }* @main.int16SliceDst
; equivalent of:
; copy(int16SliceDst, int16SliceSrc)
%int16SliceSrc.buf = extractvalue { ptr, i64, i64 } %int16SliceSrc, 0
%copy.n2 = call i64 @runtime.sliceCopy(ptr %int16SliceDst.buf, ptr %int16SliceSrc.buf, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
; Copy slice that has a known value.
%copy.n3 = call i64 @runtime.sliceCopy(ptr @main.sliceDstUntaint.buf, ptr @main.sliceSrcUntaint.buf, i64 2, i64 2, i64 1)
; Copy slice that might have been modified by the external @use call.
; This is a fix for https://github.com/tinygo-org/tinygo/issues/3890.
call void @use(ptr @main.sliceSrcTaint.buf)
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
%int16SliceSrc.buf = extractvalue { i16*, i64, i64 } %int16SliceSrc, 0
%int16SliceSrc.buf.i8ptr = bitcast i16* %int16SliceSrc.buf to i8*
%int16SliceDst.buf.i8ptr = bitcast i16* %int16SliceDst.buf to i8*
%copy.n2 = call i64 @runtime.sliceCopy(i8* %int16SliceDst.buf.i8ptr, i8* %int16SliceSrc.buf.i8ptr, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
ret void
}

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