Compare commits

..

27 Commits

Author SHA1 Message Date
Patricio Whittingslow cc959c5aab fix targets list 2026-02-25 12:49:07 -03:00
Patricio Whittingslow ef77ed3103 show number of different APIs in red 2026-02-25 12:29:37 -03:00
Patricio Whittingslow ca2694c5d9 add tgdoc tool 2026-02-25 12:21:09 -03:00
Micah Cowell fd1d10c9b7 export UART0 and pins 2026-02-19 07:17:51 +01:00
Nia Waldvogel 5c37d1ba61 runtime: implement fminimum/fmaximum
The compiler may generate calls to fminimum/fmaximum on some platforms.
Neither of the libm implementations we statically link against have these functions yet.
Implement them ourselves.
2026-02-18 15:13:01 -05:00
Dima Jolkin 610dd19c40 esp32s3-usbserial: move InitSerial to init method 2026-02-17 20:42:23 +01:00
Dima Jolkin 44ca224056 esp32s3-usbserial: common usbserial for both esp32c3 & esp32s3 2026-02-17 20:42:23 +01:00
Dima Jolkin c1cddffbe9 esp32s3-usbserial: split usb 2026-02-17 20:42:23 +01:00
Dima Jolkin 9bbad6700b esp32s3-usbserial: added usbserial printing 2026-02-17 20:42:23 +01:00
deadprogram 24f965425d make: remove machine without board from smoketest
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-16 20:51:03 +01:00
deadprogram b6b723aeec targets: correct name/tag use for esp32s3-wroom1 board
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-16 20:51:03 +01:00
deadprogram 934d5f41bf fix: init heap before random number seed on wasm platforms
This changes the order for initialization of the random number
seed generation on wasm platforms until after the heap has been
initialized. Should fix #5198

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-16 08:38:17 +01:00
Dima 4b0e858964 Esp32s3 implement spi (#5169)
* esp32s3 spi

* stabilization freq cpu

* cheange clacl freq for spi

* fix linters

* esp32s3-spi: change default pins for esp32s3 xiao

* set default configuration

* esp32s3-spi: extends smoketests for esp32s3
2026-02-15 14:50:39 +01:00
deadprogram 32378537b8 sponsorship: add explicit callout/link in README to help out TinyGo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-12 12:40:27 +01:00
Elias Naur f5b2a08b15 builder: order embedded files deterministically 2026-02-11 19:27:57 +01:00
Elias Naur f23e18a8de flake.*: bump to nixpkgs 25.11
Bump the GitHub Actions Nix install as well; nixpkgs 25.11 requires a
newer nix command.
2026-02-10 17:24:35 +01:00
deadprogram 66d7099c96 build: update CI builds to use latest Go 1.25.7 release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-04 18:56:52 +01:00
Matthew Hiles bef0dc5d21 Add per-byte timeout budget for rp2 I2C (#5189)
* Add per-byte timeout budget for rp2 I2C

* run goimports
2026-02-02 14:09:34 +01:00
Yaj e79cdc1122 targets: Add Shrike Lite board (#5170)
* feat: Add Vicharak Shrike Lite

* Add shrike-lite to smoketest
2026-01-24 08:04:22 +01:00
robo f0256cab18 Fix syntax for building with TinyGo 2026-01-23 18:01:52 +00:00
Jesús Espino 5d8e071bfb machine/attiny85: add USI-based SPI support (#5181)
* machine/attiny85: add USI-based SPI support

Implement SPI communication for ATTiny85 using the USI (Universal Serial
Interface) hardware in three-wire mode. The ATTiny85 lacks dedicated SPI
hardware but can emulate SPI using the USI module with software clock
strobing.

Implementation details:
- Configure USI in three-wire mode for SPI operation
- Use clock strobing technique to shift data in/out
- Pin mapping: PB2 (SCK), PB1 (MOSI/DO), PB0 (MISO/DI)
- Support both Transfer() and Tx() methods

The implementation uses the USI control register (USICR) to toggle the
clock pin, which triggers automatic bit shifting in hardware. This is
more efficient than pure software bit-banging.

Current limitations:
- Frequency configuration not yet implemented (runs at max software speed)
- Only SPI Mode 0 (CPOL=0, CPHA=0) supported
- Only MSB-first bit order supported

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Co-authored-by: Ona <no-reply@ona.com>

* machine/attiny85: add SPI frequency configuration support

Add software-based frequency control for USI SPI. The ATtiny85 USI lacks
hardware prescalers, so frequency is controlled via delay loops between
clock toggles.

- Calculate delay cycles based on requested frequency and CPU clock
- Fast path (no delay) when frequency is 0 or max speed requested
- Delay loop uses nop instructions for timing control

Co-authored-by: Ona <no-reply@ona.com>

* machine/attiny85: add SPI mode configuration support

Add support for all 4 SPI modes (Mode 0-3) using USI hardware:
- Mode 0 (CPOL=0, CPHA=0): Clock idle low, sample on rising edge
- Mode 1 (CPOL=0, CPHA=1): Clock idle low, sample on falling edge
- Mode 2 (CPOL=1, CPHA=0): Clock idle high, sample on falling edge
- Mode 3 (CPOL=1, CPHA=1): Clock idle high, sample on rising edge

CPOL is controlled by setting the clock pin idle state.
CPHA is controlled via the USICS0 bit in USICR.

Co-authored-by: Ona <no-reply@ona.com>

* machine/attiny85: add LSB-first bit order support

Add software-based LSB-first support for USI SPI. The USI hardware only
supports MSB-first, so bit reversal is done in software before sending
and after receiving.

Uses an efficient parallel bit swap algorithm (3 operations) to reverse
the byte.

Co-authored-by: Ona <no-reply@ona.com>

* GNUmakefile: add mcp3008 SPI example to digispark smoketest

Test the USI-based SPI implementation for ATtiny85/digispark.

Co-authored-by: Ona <no-reply@ona.com>

* machine/attiny85: minimize SPI RAM footprint

Reduce SPI struct from ~14 bytes to 1 byte to fit in ATtiny85's limited
512 bytes of RAM.

Changes:
- Remove register pointers (use avr.USIDR/USISR/USICR directly)
- Remove pin fields (USI pins are fixed: PB0/PB1/PB2)
- Remove CS pin management (user must handle CS)
- Remove frequency control (runs at max speed)
- Remove LSBFirst support

The SPI struct now only stores the USICR configuration byte.

Co-authored-by: Ona <no-reply@ona.com>

* Revert "machine/attiny85: minimize SPI RAM footprint"

This reverts commit 387ccad494.

Co-authored-by: Ona <no-reply@ona.com>

* machine/attiny85: reduce SPI RAM usage by 10 bytes

Remove unnecessary fields from SPI struct while keeping all functionality:
- Remove register pointers (use avr.USIDR/USISR/USICR directly)
- Remove pin fields (USI pins are fixed: PB0/PB1/PB2)
- Remove CS pin (user must manage it, standard practice)

Kept functional fields:
- delayCycles for frequency control
- usicrValue for SPI mode support
- lsbFirst for bit order support

SPI struct reduced from 14 bytes to 4 bytes.

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-01-17 21:22:15 +01:00
Damian Gryski a0069b6282 testdata: more corpus entries (#5182)
* testdata: more corpus entries

* testdata: remove skipwasi for dchest/siphash build issues
2026-01-17 17:59:13 +01:00
deadprogram 707d37a4c1 chore: update version to 0.41.0-dev
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-01-14 13:09:19 +00:00
Nia Waldvogel 1876b65b18 compiler: simplify createObjectLayout
This simplifies the process of constructing and encoding layout bitmaps.
Instead of creating big integers and merging them, we can create a pre-sized bitmap and set positions within it.

This also changes the encoding logic to allow larger layouts to be encoded inline.
We would previously not encode a layout inline unless the size was less than the width of the data field.
This is overly conservative.
A layout can be encoded inline as long as:
1. The size fits within the size field.
2. All set bits in the bitmap fit into the data field.
2026-01-14 08:52:09 +00:00
deadprogram 1fe934e8a8 machine/rp: add Close function to UART to allow for removing all system resources/power usage
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-01-13 22:58:37 +00:00
deadprogram 8bd2233b57 machine/rp: use the blockReset() and unresetBlockWait() helper functions for all peripheral reset/unreset operations
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-01-13 08:55:10 +00:00
Jesús Espino ff58c50118 machine: add attiny85 pwm support (#5171)
* machine/attiny85: add PWM support for Timer0 and Timer1

Add complete PWM implementation for ATtiny85, supporting both Timer0
and Timer1 with their respective output channels:
- Timer0: 8-bit timer for pins PB0 (OC0A) and PB1 (OC0B)
- Timer1: 8-bit high-speed timer for pins PB1 (OC1A) and PB4 (OC1B)

Timer1 provides more flexible period control with configurable top value
(OCR1C) and extended prescaler options (1-16384), making it well-suited
for LED PWM control and other applications requiring variable frequencies.

Implements full PWM interface including Configure, SetPeriod, Channel,
Set, SetInverting, Top, Counter, and Period methods.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* machine/digispark: document PWM support on pins

Add documentation to the Digispark board file indicating which pins
support PWM output:
- P0 (PB0): Timer0 channel A
- P1 (PB1): Timer0 channel B or Timer1 channel A
- P4 (PB4): Timer1 channel B

Includes package comment explaining Timer0 vs Timer1 capabilities,
with Timer1 recommended for more flexible frequency control.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* machine/attiny85: optimize PWM prescaler lookups

Replace verbose switch statements with more efficient implementations:

- SetPeriod: Use bit shift (top >>= prescaler-1) instead of 15-case
  switch for dividing uint64 by power-of-2 prescaler values

- Period: Replace switch statements with compact uint16 lookup tables
  for both Timer0 and Timer1, casting to uint64 only when needed

This addresses review feedback about inefficient switch-based lookups.
On AVR, this approach is significantly smaller:
- Bit shifts for uint64 division: ~34 bytes vs ~140 bytes
- uint16 tables: 22 bytes code + 32/16 bytes data vs ~140 bytes
- Total savings: ~190 bytes (68% reduction)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* examples/pwm: add digispark support and smoketest

Add digispark.go configuration for PWM example using Timer1 with pins P1 (LED) and P4. Also add digispark PWM example to GNUmakefile smoketests.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 13:38:20 +01:00
416 changed files with 6104 additions and 21301 deletions
+119
View File
@@ -0,0 +1,119 @@
version: 2.1
commands:
submodules:
steps:
- run:
name: "Pull submodules"
command: git submodule update --init
llvm-source-linux:
steps:
- restore_cache:
keys:
- llvm-source-19-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-19-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/compiler-rt
- llvm-project/lld/include
- llvm-project/llvm/include
hack-ninja-jobs:
steps:
- run:
name: "Hack Ninja to use less jobs"
command: |
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
chmod +x /go/bin/ninja
build-binaryen-linux:
steps:
- restore_cache:
keys:
- binaryen-linux-v3
- run:
name: "Build Binaryen"
command: |
make binaryen
- save_cache:
key: binaryen-linux-v3
paths:
- build/wasm-opt
test-linux:
parameters:
llvm:
type: string
fmt-check:
type: boolean
default: true
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
echo 'deb https://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update
apt-get install --no-install-recommends -y \
llvm-<<parameters.llvm>>-dev \
clang-<<parameters.llvm>> \
libclang-<<parameters.llvm>>-dev \
lld-<<parameters.llvm>> \
cmake \
ninja-build
- hack-ninja-jobs
- build-binaryen-linux
- restore_cache:
keys:
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v4-{{ checksum "go.mod" }}
- llvm-source-linux
- run: go install -tags=llvm<<parameters.llvm>> .
- when:
condition: <<parameters.fmt-check>>
steps:
- run:
# Do this before gen-device so that it doesn't check the
# formatting of generated files.
name: Check Go code formatting
command: make fmt-check lint
- run: make gen-device -j4
# TODO: change this to -skip='TestErrors|TestWasm' with Go 1.20
- run: go test -tags=llvm<<parameters.llvm>> -short -run='TestBuild|TestTest|TestGetList|TestTraceback'
- run: make smoketest XTENSA=0
- save_cache:
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
jobs:
test-oldest:
# This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass.
docker:
- image: golang:1.22-bullseye
steps:
- test-linux:
llvm: "15"
resource_class: large
test-newest:
# This tests the latest supported LLVM version when linking against system
# libraries.
docker:
- image: golang:1.25-bullseye
steps:
- test-linux:
llvm: "20"
resource_class: large
workflows:
test-all:
jobs:
- test-oldest
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
# - test-newest
+1
View File
@@ -1,4 +1,5 @@
build/ build/
llvm-*/ llvm-*/
.github .github
.circleci
+16 -12
View File
@@ -31,7 +31,7 @@ jobs:
run: | run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
@@ -40,10 +40,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-${{ matrix.os }}-v1 key: llvm-source-20-${{ matrix.os }}-v1
@@ -57,7 +57,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -68,7 +68,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-${{ matrix.os }}-v2 key: llvm-build-20-${{ matrix.os }}-v2
@@ -85,7 +85,7 @@ jobs:
make llvm-build make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
@@ -101,11 +101,16 @@ jobs:
- name: Make release artifact - name: Make release artifact
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v7 # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a double-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with: with:
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }} name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
archive: false
- name: Smoke tests - name: Smoke tests
run: make smoketest TINYGO=$(PWD)/build/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew: test-macos-homebrew:
@@ -116,7 +121,7 @@ jobs:
version: [16, 17, 18, 19, 20] version: [16, 17, 18, 19, 20]
steps: steps:
- name: Set up Homebrew - name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@main uses: Homebrew/actions/setup-homebrew@master
- name: Fix Python symlinks - name: Fix Python symlinks
run: | run: |
# Github runners have broken symlinks, so relink # Github runners have broken symlinks, so relink
@@ -125,13 +130,12 @@ jobs:
- name: Install LLVM - name: Install LLVM
run: | run: |
brew install llvm@${{ matrix.version }} brew install llvm@${{ matrix.version }}
brew link llvm@${{ matrix.version }}
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }} run: go install -tags=llvm${{ matrix.version }}
-72
View File
@@ -1,72 +0,0 @@
# This CI job checks whether at least the smoke tests pass for the oldest
# Go/LLVM version we claim to support.
name: Version compatibility test
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test-compat:
runs-on: ubuntu-22.04 # this must be a specific version for the apt install below
env:
# Oldest versions currently supported by TinyGo
LLVM: "15"
Go: "1.24" # when updating this, also update minorMin in builder/config.go
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: ${{ env.Go }}
cache: true
- name: Install LLVM
run: |
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ env.LLVM }} 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-${{ env.LLVM }}-dev \
clang-${{ env.LLVM }} \
libclang-${{ env.LLVM }}-dev \
lld-${{ env.LLVM }} \
binaryen
- name: Restore LLVM source cache
uses: actions/cache/restore@v5
id: cache-llvm-source
with:
key: llvm-source-20-linux-compat
path: llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v5
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: llvm-project/compiler-rt
- name: Go cache
uses: actions/cache@v5
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: go-build-${{ env.Go }}-llvm${{ env.LLVM }}-${{ hashFiles('go.sum') }}
- name: Build TinyGo
run: go install -tags=llvm${{ env.LLVM }}
- run: tinygo version
- run: make gen-device -j4
- run: go test -tags=llvm${{ env.LLVM }} -short -skip=TestErrors
- run: make smoketest XTENSA=0
+6 -6
View File
@@ -31,14 +31,14 @@ jobs:
sudo rm -rf /usr/local/share/boost sudo rm -rf /usr/local/share/boost
df -h df -h
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: recursive submodules: recursive
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
tinygo/tinygo-dev tinygo/tinygo-dev
@@ -47,18 +47,18 @@ jobs:
type=sha,format=long type=sha,format=long
type=raw,value=latest type=raw,value=latest
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry - name: Log in to Github Container Registry
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: . context: .
push: true push: true
+48 -78
View File
@@ -12,36 +12,18 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
go-mod-tidy:
# Check that go.sum is up to date.
runs-on: ubuntu-slim
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: '1.26.4'
cache: true
- name: Run go mod tidy
run: go mod tidy
- name: Check go.mod and go.sum are up to date
run: git diff --exit-code
build-linux: build-linux:
# Build Linux binaries, ready for release. # Build Linux binaries, ready for release.
# This runs inside an Alpine Linux container so we can more easily create a # This runs inside an Alpine Linux container so we can more easily create a
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.26-alpine image: golang:1.25-alpine
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Install apk dependencies - name: Install apk dependencies
# tar: needed for actions/cache@v5 # tar: needed for actions/cache@v4
# git+openssh: needed for checkout (I think?) # git+openssh: needed for checkout (I think?)
# ruby: needed to install fpm # ruby: needed to install fpm
run: apk add tar git openssh make g++ ruby-dev mold run: apk add tar git openssh make g++ ruby-dev mold
@@ -49,24 +31,24 @@ jobs:
# We're not on a multi-user machine, so this is safe. # We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE" run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
id: version id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT" run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Cache Go - name: Cache Go
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-linux-alpine-v2-${{ hashFiles('go.mod') }} key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
path: | path: |
~/.cache/go-build ~/.cache/go-build
~/go/pkg/mod ~/go/pkg/mod
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-alpine-v2 key: llvm-source-20-linux-alpine-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -77,7 +59,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -88,10 +70,10 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-alpine-v2 key: llvm-build-20-linux-alpine-v1
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -106,16 +88,16 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-alpine-v2 key: binaryen-linux-alpine-v1
path: build/wasm-opt path: build/wasm-opt
- name: Build Binaryen - name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true' if: steps.cache-binaryen.outputs.cache-hit != 'true'
@@ -136,31 +118,26 @@ jobs:
make release deb -j3 STATIC=1 make release deb -j3 STATIC=1
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
- name: "Publish release artifact: tarball" - name: Publish release artifact
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz name: linux-amd64-double-zipped-${{ steps.version.outputs.version }}
path: /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz path: |
archive: false /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
- name: "Publish release artifact: Debian package" /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
uses: actions/upload-artifact@v7
with:
name: tinygo_${{ steps.version.outputs.version }}_amd64.deb
path: /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
archive: false
test-linux-build: test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests. # Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build-linux needs: build-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -169,9 +146,9 @@ jobs:
- name: Install wasm-tools - name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Download release artifact - name: Download release artifact
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
- name: Extract release tarball - name: Extract release tarball
run: | run: |
mkdir -p ~/lib mkdir -p ~/lib
@@ -187,7 +164,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Install apt dependencies - name: Install apt dependencies
@@ -204,10 +181,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '18'
- name: Install wasmtime - name: Install wasmtime
@@ -217,7 +194,7 @@ jobs:
- name: Setup `wasm-tools` - name: Setup `wasm-tools`
uses: bytecodealliance/actions/wasm-tools/setup@v1 uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-asserts-v1 key: llvm-source-20-linux-asserts-v1
@@ -231,7 +208,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -242,7 +219,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-asserts-v1 key: llvm-build-20-linux-asserts-v1
@@ -258,13 +235,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-asserts-v1 key: binaryen-linux-asserts-v1
@@ -284,8 +261,6 @@ jobs:
- run: make smoketest - run: make smoketest
- run: make wasmtest - run: make wasmtest
- run: make tinygo-test-baremetal - run: make tinygo-test-baremetal
- name: Check Go code formatting
run: make fmt-check lint
build-linux-cross: build-linux-cross:
# Build ARM Linux binaries, ready for release. # Build ARM Linux binaries, ready for release.
# This intentionally uses an older Linux image, so that we compile against # This intentionally uses an older Linux image, so that we compile against
@@ -309,7 +284,7 @@ jobs:
needs: build-linux needs: build-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Get TinyGo version - name: Get TinyGo version
id: version id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT" run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
@@ -323,10 +298,10 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-v1 key: llvm-source-20-linux-v1
@@ -340,7 +315,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -351,7 +326,7 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore LLVM build cache - name: Restore LLVM build cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-linux-${{ matrix.goarch }}-v1 key: llvm-build-20-linux-${{ matrix.goarch }}-v1
@@ -369,13 +344,13 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache - name: Save LLVM build cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-${{ matrix.goarch }}-v4 key: binaryen-linux-${{ matrix.goarch }}-v4
@@ -395,9 +370,9 @@ jobs:
run: | run: |
make CROSS=${{ matrix.toolchain }} make CROSS=${{ matrix.toolchain }}
- name: Download amd64 release - name: Download amd64 release
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
- name: Extract amd64 release - name: Extract amd64 release
run: | run: |
mkdir -p build/release mkdir -p build/release
@@ -409,17 +384,12 @@ jobs:
- name: Create ${{ matrix.goarch }} release - name: Create ${{ matrix.goarch }} release
run: | run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }} make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
- name: "Publish release artifact: tarball" - name: Publish release artifact
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v4
with: with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }} name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
path: /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz path: |
archive: false /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
- name: "Publish release artifact: Debian package" /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
uses: actions/upload-artifact@v7
with:
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
path: /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
archive: false
+5 -5
View File
@@ -25,14 +25,14 @@ jobs:
contents: read contents: read
steps: steps:
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: recursive submodules: recursive
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
tinygo/llvm-20 tinygo/llvm-20
@@ -46,13 +46,13 @@ jobs:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry - name: Log in to Github Container Registry
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
target: tinygo-llvm-build target: tinygo-llvm-build
context: . context: .
+3 -3
View File
@@ -21,12 +21,12 @@ jobs:
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668 # See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
run: sudo apt-get remove llvm-18 run: sudo apt-get remove llvm-18
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Pull musl, bdwgc - name: Pull musl, bdwgc
run: | run: |
git submodule update --init lib/musl lib/bdwgc git submodule update --init lib/musl lib/bdwgc
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-linux-nix-v1 key: llvm-source-20-linux-nix-v1
@@ -36,7 +36,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save LLVM source cache - name: Save LLVM source cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
run: | run: |
echo "$HOME/go/bin" >> $GITHUB_PATH echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
fetch-depth: 0 # fetch all history (no sparse checkout) fetch-depth: 0 # fetch all history (no sparse checkout)
submodules: true submodules: true
- name: Install apt dependencies - name: Install apt dependencies
run: ./.github/workflows/sizediff-install-pkgs.sh run: ./.github/workflows/sizediff-install-pkgs.sh
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache@v5 uses: actions/cache@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-sizediff-v1 key: llvm-source-20-sizediff-v1
@@ -37,7 +37,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache Go - name: Cache Go
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }} key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
path: | path: |
+73 -33
View File
@@ -17,14 +17,21 @@ jobs:
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true
scoop install ninja binaryen scoop install ninja binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
with: with:
submodules: true submodules: true
- name: Extract TinyGo version - name: Extract TinyGo version
@@ -34,13 +41,13 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Restore cached LLVM source - name: Restore cached LLVM source
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-20-windows-v3 key: llvm-source-20-windows-v1
path: | path: |
llvm-project/clang/lib/Headers llvm-project/clang/lib/Headers
llvm-project/clang/include llvm-project/clang/include
@@ -51,7 +58,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Save cached LLVM source - name: Save cached LLVM source
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
@@ -62,10 +69,10 @@ jobs:
llvm-project/lld/include llvm-project/lld/include
llvm-project/llvm/include llvm-project/llvm/include
- name: Restore cached LLVM build - name: Restore cached LLVM build
uses: actions/cache/restore@v5 uses: actions/cache/restore@v4
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-20-windows-v4 key: llvm-build-20-windows-v2
path: llvm-build path: llvm-build
- name: Build LLVM - name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -79,21 +86,20 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save cached LLVM build - name: Save cached LLVM build
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true' if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with: with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }} key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build path: llvm-build
- name: Cache Go cache - name: Cache Go cache
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
key: go-cache-windows-v3-${{ hashFiles('go.mod') }} key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
path: | path: |
C:/Users/runneradmin/AppData/Local/go-build C:/Users/runneradmin/AppData/Local/go-build
C:/Users/runneradmin/go/pkg/mod C:/Users/runneradmin/go/pkg/mod
- name: Install wasmtime - name: Install wasmtime
run: | run: |
scoop config use_external_7zip true
scoop install wasmtime@29.0.1 scoop install wasmtime@29.0.1
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make -j3 gen-device
@@ -108,35 +114,50 @@ jobs:
working-directory: build/release working-directory: build/release
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo
- name: Publish release artifact - name: Publish release artifact
uses: actions/upload-artifact@v7 # Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a dobule-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with: with:
name: tinygo${{ steps.version.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ steps.version.outputs.version }}
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
archive: false
smoke-test-windows: smoke-test-windows:
runs-on: windows-2022 runs-on: windows-2022
needs: build-windows needs: build-windows
steps: steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true
scoop install binaryen scoop install binaryen
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ path: build/
# This build is already unzipped. - name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Smoke tests - name: Smoke tests
shell: bash shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -145,19 +166,28 @@ jobs:
runs-on: windows-2022 runs-on: windows-2022
needs: build-windows needs: build-windows
steps: steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ path: build/
# This build is already unzipped. - name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
@@ -165,24 +195,34 @@ jobs:
runs-on: windows-2022 runs-on: windows-2022
needs: build-windows needs: build-windows
steps: steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: MinoruSekine/setup-scoop@v4 - uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop config use_external_7zip true scoop install binaryen && scoop install wasmtime@29.0.1
scoop install binaryen wasmtime@29.0.1
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.26.4' go-version: '1.25.7'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
path: build/ path: build/
# This build is already unzipped. - name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x tinygo*.windows-amd64.zip -r
- name: Test stdlib packages on wasip1 - name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
-157
View File
@@ -1,160 +1,3 @@
0.41.1
---
* **machine**
- esp32c3: correct pin interrupt setup call that was overlooked from #5320
* **runtime**
- esp32s3: wait for TIMG0 update register to clear before reading timer registers
* **net**
- update net module to a version that is backwards compatible with Go 1.25.x to fix #5332
0.41.0
---
* **general**
- go.mod, compiler: bump minimum Go version to 1.23
- builder: support Go 1.26 now
- feat: add inheritable-only field to filter processor-level targets (#5270)
- feature: add esp32flash flash method for esp32s3/esp32c3/esp32/esp8266
- flashing: introduce flash method 'esp32jtag' for esp32c3/esp32s3 targets
- fashing: add "adb" flash method using Android Debug Bridge
- main: auto-use best available flashing options on esp32
- espflasher: update to espflasher 0.6.0
* **compiler**
- implement method-set based AssignableTo and Implements (#5304)
- simplify createObjectLayout
- implement copy directly
- fix min/max on floats by using intrinsics
- add element layout to sliceAppend
- add intrinsic for crypto/internal/constanttime.boolToUint8
- fix SyscallN handling for Windows on Go 1.26+
* **core**
- reflect: add TypeAssert
- reflect: fix TypeAssert for structs
- sync: add WaitGroup.Go
- os: add UserCacheDir and UserConfigDir
- os: implement Lchown function for changing file ownership (#5161)
- testing: add b.ReportMetric()
- errors: add errors package to passing list
- internal/gclayout: use correct lengths
- internal/abi: add EscapeNonString, EscapeToResultNonString
- internal, runtime: add internal fips bool
- internal/itoa: resurrect from Go stdlib
- internal/syscall/unix: implement GetRandom for WASI targets
- interp: make ptrtoint size mismatch a recoverable error
- loader: support "all:" prefix in //go:embed patterns
- loader, crypto/internal/entropy: fix 32 MiB RAM overflow on microcontrollers
- loader, unicode/utf8: fix hiBits overflow on 16-bit AVR targets
- builder: order embedded files deterministically
- builder: fix panic in findPackagePath when using -size short
- builder: fix SIGSEGV when stripping duplicate function definitions
- builder, runtime: fix duplicate symbol error with Go 1.26+ on Windows
- builder: use target-specific -march for RISC-V library compilation
- transform: modify output format from the -print-allocs flag to match the go coverage tool format
- cgo: allow for changes to 'short-enums' flag
- wasm: add more stubbed file operations
* **machine**
- esp32c3: implement BlockDevice for esp32c3 flash
- esp32c3: clear GPIO STATUS before dispatching pin callbacks
- esp32c3: implement USBDevice using interrupts
- esp32c3: add Enable stub for QEMU test target
- esp32c3: fix interrupt disable handling
- esp32c3: clear MCAUSE after handling interrupt
- esp32c3: map missing IRAM sections in linker script
- esp32c3: fix to use PROVIDE() for WiFi/BLE ROM function addresses to allow blob overrides
- esp32c3: add WiFi/BLE ROM linker support
- esp32c3: use TIMG0 alarm interrupt for sleepTicks instead of busy-waiting
- esp32s3: implement Pin.SetInterrupt for GPIO pin change interrupts
- esp32s3: use edge-triggered CPU interrupt for GPIO pin interrupts
- esp32s3: add interrupt support (#5244)
- esp32s3: switch USB implementation to use interrupts instead of polling
- esp32s3: replace inline ISR with full interrupt vector handler
- esp32s3: use TIMG0 alarm interrupt for sleepTicks
- esp32s3: improve exception handlers, add procPin/procUnpin, and linker wrap flags
- esp32s3: fix Xtensa register window spill using recursive call4 in task switching
- esp32s3: update linker script and boot assembly for multi-page flash XIP mapping
- esp32s3: add flash XIP boot assembly with cache/MMU init
- esp32s3: implement SPI (#5169)
- esp32s3: implement I2C interface (#5210)
- esp32s3: implement RNG based on onboard hardware random number generator
- esp32s3,esp32c3: add USB serial support
- esp32s3,esp32c3: add txStalled flag to skip USB serial spin when no host
- esp32s3,esp32c3: make USB Serial/JTAG writes non-blocking when FIFO is full
- esp32c3/esp32s3: refactor ADC implementation to reduce code duplication
- esp32s3,esp32c3: add ADC support (#5231)
- esp32s3,esp32c3: add PWM support (#5215)
- esp32c3/esp32s3: refactoring and corrections for SPI implementation
- esp32xx: add WASM simulator support for ESP32-C3/ESP32-S3 targets
- esp32: default SPI CS pin to NoPin when unset
- esp: fix tinygo_scanCurrentStack to spill register windows
- stm32: fix UART interrupt storm caused by uncleared overrun error
- stm32: fix PWM problem due to register shifting
- stm32: add STM32U585 target definition and runtime
- stm32: add STM32U5 GPIO, pin interrupts, and UART support
- stm32: add STM32U5 I2C support
- stm32: add STM32U5 SPI support
- stm32u585: implement ADC
- stm32g0b1: add support (#5150)
- stm32g0b1: add Watchdog + ADC support (#5158)
- stm32l0: add flash support
- stm32l0x1,l0x2: TIM: adapt to 32-bit register access
- stm32g0: sync with updated stm32 device files
- attiny85: add USI-based SPI support (#5181)
- attiny85: add PWM support (#5171)
- rp: add Close function to UART to allow for removing all system resources/power usage
- rp: use blockReset() and unresetBlockWait() helper functions for peripheral reset/unreset
- rp2: prevent PWM Period method overflow
- rp2: add per-byte timeout budget for I2C (#5189)
- feather-m0: export UART0 and pins
- usb/cdc: better ring buffer implementation (#5209)
- fix: replace ! with ~ for register mask
- atmega328p_simulator: add correct build tag for arduino_uno after renaming
* **net**
- update to Go 1.26.2 net package with UDP and JS improvements
* **runtime**
- implement fminimum/fmaximum
- make timeoffset atomic
- add MemStats.HeapObjects
- handle GODEBUG on wasip2 (#5312)
- fix Darwin syscall return value truncation and lost arguments
- add syscall.runtimeClearenv for Go 1.26
- split syscall functions for darwin changes for 1.26
- fix: init heap before random number seed on wasm platforms
* **targets**
- add esp32s3-supermini board target
- add support for Seeedstudio Xiao-RP2350 board
- add Shrike Lite board (#5170)
- rename arduino target to arduino-uno
- add pins/setup for Arduino UNO Q board QWIIC connector
- correct pin mapping for Arduino UNO Q STM32 MCU
- add stm32u585 openocd commands for flashing on Arduino UNO Q
- correct name/tag use for esp32s3-wroom1 board
- modify esp32, esp32s3, esp32c3, & esp8266 targets to use built-in esp32flash
- switch rp2040/rp2350 to default to tasks scheduler
- change default stack size for esp32c3 and esp32s3 to 8196
- swan: rename group build tag stm32l4x5 => stm32l4y5 to avoid clash with stm32 device name
- nucleo-f722ze: add build-tag stm32f722
- fix: set stm32u5x clock rate to default
- create generic targets for esp32 boards
* **libs**
- stm32-svd: update submodule
- update tools/gen-device-svd for recent changes to stm32-svd file structure (#5212)
* **build/test**
- build: use Golang 1.26 for all builds
- build: actually use the version of llvm we are supposed to be testing by using brew link command
- build: let scoop run updates to resolve binaryen install failures on Windows
- ci: don't double zip release artifacts
- test: increase default timeout from 1 to 2 minutes to prevent spurious CI fails
- testdata: fix flaky timers test by draining ticker channel after Stop
- testdata: more corpus entries (#5182)
- add soypat/lneto to corpus
- GNUmakefile: add context and expvar to stdlib tests
- GNUmakefile: add encoding/xml to stdlib tests on Linux
- main (test): skip mipsle test if the emulator is missing
- make: remove machine without board from smoketest
- stm32: add Arduino UNO Q to smoketests
- flake: bump to nixpkgs 25.11
- chore: update all github actions to latest versions
- fix: use external 7zip for scoop installs on Windows
0.40.1 0.40.1
--- ---
* **machine** * **machine**
+2 -2
View File
@@ -1,5 +1,5 @@
# tinygo-llvm stage obtains the llvm source for TinyGo # tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.26 AS tinygo-llvm FROM golang:1.25 AS tinygo-llvm
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-17 ninja-build && \ apt-get install -y apt-utils make cmake clang-17 ninja-build && \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without # tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc). # all the build tools etc).
FROM golang:1.26 AS tinygo-compiler FROM golang:1.25 AS tinygo-compiler
# Copy tinygo build. # Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+19 -92
View File
@@ -194,12 +194,6 @@ NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm lld $(addprefix lib/lib,
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","") ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include CGO_CPPFLAGS+=$(shell $(LLVM_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++17
ifneq ($(uname),Windows_NT)
# Disable GCC DWARF compression: lld built without zlib cannot link
# object files with ELFCOMPRESS_ZLIB debug sections.
CGO_CFLAGS+=-gz=none
CGO_CXXFLAGS+=-gz=none
endif
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA) CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif endif
@@ -295,13 +289,13 @@ WASM_TOOLS_MODULE=go.bytecodealliance.org
.PHONY: wasi-syscall .PHONY: wasi-syscall
wasi-syscall: wasi-cm wasi-syscall: wasi-cm
rm -rf ./src/internal/wasi/* rm -rf ./src/internal/wasi/*
go run $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
# Copy package cm into src/internal/cm # Copy package cm into src/internal/cm
.PHONY: wasi-cm .PHONY: wasi-cm
wasi-cm: wasi-cm:
rm -rf ./src/internal/cm/* rm -rf ./src/internal/cm/*
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
# Check for Node.js used during WASM tests. # Check for Node.js used during WASM tests.
MIN_NODEJS_VERSION=18 MIN_NODEJS_VERSION=18
@@ -316,7 +310,7 @@ check-nodejs-version:
tinygo: ## Build the TinyGo compiler tinygo: ## Build the TinyGo compiler
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " $(MAKE) llvm-source"; echo " $(MAKE) $(LLVM_BUILDDIR)"; exit 1; fi @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_CFLAGS="$(CGO_CFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" .
test: check-nodejs-version test: check-nodejs-version
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS) CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
@@ -345,17 +339,14 @@ TEST_PACKAGES_FAST = \
embed/internal/embedtest \ embed/internal/embedtest \
encoding \ encoding \
encoding/ascii85 \ encoding/ascii85 \
errors \
encoding/asn1 \ encoding/asn1 \
encoding/base32 \ encoding/base32 \
encoding/base64 \ encoding/base64 \
encoding/csv \ encoding/csv \
encoding/hex \ encoding/hex \
expvar \
go/ast \ go/ast \
go/format \ go/format \
go/scanner \ go/scanner \
go/token \
go/version \ go/version \
hash \ hash \
hash/adler32 \ hash/adler32 \
@@ -368,7 +359,6 @@ TEST_PACKAGES_FAST = \
math/cmplx \ math/cmplx \
net/http/internal/ascii \ net/http/internal/ascii \
net/mail \ net/mail \
net/url \
os \ os \
path \ path \
reflect \ reflect \
@@ -385,35 +375,32 @@ TEST_PACKAGES_FAST = \
# archive/zip requires os.ReadAt, which is not yet supported on windows # archive/zip requires os.ReadAt, which is not yet supported on windows
# bytes requires mmap # bytes requires mmap
# compress/flate appears to hang on wasi # compress/flate appears to hang on wasi
# crypto/aes needs reflect.Type.Method(), not yet implemented # crypto/aes fails on wasi, needs panic()/recover()
# crypto/des fails on wasi, needs panic()/recover() # crypto/des fails on wasi, needs panic()/recover()
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic # crypto/hmac fails on wasi, it exits with a "slice out of range" panic
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows # debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# encoding/xml takes a minute on linux and gives a stack overflow on wasi # image requires recover(), which is not yet supported on wasi
# image fails on wasi, needs panic()/recover()
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi # io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# mime: fails on wasi, needs panic()/recover() # mime: fail on wasi; neds panic()/recover()
# mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK # mime/multipart: needs wasip1 syscall.FDFLAG_NONBLOCK
# mime/quotedprintable requires syscall.Faccessat # mime/quotedprintable requires syscall.Faccessat
# net/mail: needs wasip1 syscall.FDFLAG_NONBLOCK # net/mail: needs wasip1 syscall.FDFLAG_NONBLOCK
# net/ntextproto: needs wasip1 syscall.FDFLAG_NONBLOCK # net/ntextproto: needs wasip1 syscall.FDFLAG_NONBLOCK
# regexp/syntax: fails on wasip1, needs panic()/recover() # regexp/syntax: fails on wasip1; needs panic()/recover()
# strconv: fails on wasi, needs panic()/recover() # strconv requires recover() which is not yet supported on wasi
# text/tabwriter: fails on wasi, needs panic()/recover() # text/tabwriter requires recover(), which is not yet supported on wasi
# text/template/parse: fails on wasi, needs panic()/recover() # text/template/parse requires recover(), which is not yet supported on wasi
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi # testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
# Additional standard library packages that pass tests on individual platforms # Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \ TEST_PACKAGES_LINUX := \
archive/zip \ archive/zip \
compress/flate \ compress/flate \
context \
crypto/aes \ crypto/aes \
crypto/des \ crypto/des \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
encoding/xml \
image \ image \
io/ioutil \ io/ioutil \
mime \ mime \
@@ -425,7 +412,6 @@ TEST_PACKAGES_LINUX := \
os/user \ os/user \
regexp/syntax \ regexp/syntax \
strconv \ strconv \
testing/fstest \
text/tabwriter \ text/tabwriter \
text/template/parse text/template/parse
@@ -436,11 +422,7 @@ TEST_PACKAGES_WINDOWS := \
compress/flate \ compress/flate \
crypto/des \ crypto/des \
crypto/hmac \ crypto/hmac \
image \
mime \
regexp/syntax \
strconv \ strconv \
text/tabwriter \
text/template/parse \ text/template/parse \
$(nil) $(nil)
@@ -455,7 +437,6 @@ TEST_PACKAGES_NONWASM = \
crypto/ecdsa \ crypto/ecdsa \
debug/macho \ debug/macho \
embed/internal/embedtest \ embed/internal/embedtest \
expvar \
go/format \ go/format \
os \ os \
testing \ testing \
@@ -499,7 +480,7 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false TEST_IOFS := false
endif endif
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic|TestAsValidation' TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
TEST_ADDITIONAL_FLAGS ?= TEST_ADDITIONAL_FLAGS ?=
# Test known-working standard library packages. # Test known-working standard library packages.
@@ -645,7 +626,7 @@ smoketest: testchdir
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org # test simulated boards on play.tinygo.org
ifneq ($(WASM), 0) ifneq ($(WASM), 0)
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1 GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1 GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
@@ -663,8 +644,6 @@ ifneq ($(WASM), 0)
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1 GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
@$(MD5SUM) test.wasm @$(MD5SUM) test.wasm
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=xiao_esp32s3 examples/blinky1
@$(MD5SUM) test.wasm
endif endif
# test all targets/boards # test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@@ -789,8 +768,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1 $(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico -gc=leaking examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1 $(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1
@@ -839,8 +816,6 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=vicharak_shrike-lite examples/echo $(TINYGO) build -size short -o test.hex -target=vicharak_shrike-lite examples/echo
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao-rp2350 examples/blinky1
@$(MD5SUM) test.hex
# test pwm # test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -900,24 +875,18 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial $(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinkm
@$(MD5SUM) test.hex
endif endif
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm $(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest $(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/pwm $(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-uno -scheduler=tasks examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -936,18 +905,10 @@ endif
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1 $(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
ifneq ($(XTENSA), 0) ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target=esp32-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-generic examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1 $(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest $(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
@@ -960,46 +921,13 @@ ifneq ($(XTENSA), 0)
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest $(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
# xiao-esp32c6
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c6 examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c6 examples/blinkm
@$(MD5SUM) test.bin
# xiao-esp32s3
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1 $(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008 $(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/pwm $(TINYGO) build -size short -o test.bin -target=esp32s3-wroom1 examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/adc
@$(MD5SUM) test.bin
# esp32s3-supermini
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/adc
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32s3-box-3 examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
endif endif
# esp32c3-supermini
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/mcp3008
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/pwm
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/adc
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest $(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
@@ -1012,7 +940,6 @@ endif
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1 $(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest $(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@@ -1183,8 +1110,8 @@ endif
@cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src @cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half @cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit @cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins @cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins @cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
@cp -rp src build/release/tinygo/src @cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets @cp -rp targets build/release/tinygo/targets
@@ -1206,7 +1133,7 @@ endif
.PHONY: tools .PHONY: tools
tools: tools:
go generate -tags tools ./ cd internal/tools && go generate -tags tools ./
LINTDIRS=src/os/ src/reflect/ LINTDIRS=src/os/ src/reflect/
.PHONY: lint .PHONY: lint
+5 -5
View File
@@ -1,6 +1,6 @@
# TinyGo - Go compiler for small places # TinyGo - Go compiler for small places
[![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) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml) [![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) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.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/wasi), and command-line tools.
@@ -34,10 +34,10 @@ func main() {
} }
``` ```
The above program can be compiled and run without modification on an [Arduino Uno](https://tinygo.org/docs/reference/microcontrollers/boards/arduino-uno), an [Adafruit Circuit Playground Express](https://tinygo.org/docs/reference/microcontrollers/featured/circuitplay-express), a [Seeed Studio XIAO-ESP32S3](https://tinygo.org/docs/reference/microcontrollers/featured/xiao-esp32s3) or any of the many supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno: The above program can be compiled and run without modification on an Arduino Uno, an Adafruit ItsyBitsy M0, or any of the supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
```shell ```shell
tinygo flash -target arduino-uno examples/blinky1 tinygo flash -target arduino examples/blinky1
``` ```
## WebAssembly ## WebAssembly
@@ -77,7 +77,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
### Embedded ### Embedded
You can compile TinyGo programs for over 150 different microcontroller boards. You can compile TinyGo programs for over 94 different microcontroller boards.
For more information, please see https://tinygo.org/docs/reference/microcontrollers/ For more information, please see https://tinygo.org/docs/reference/microcontrollers/
@@ -142,7 +142,7 @@ Non-goals:
## Why this project exists ## Why this project exists
> We never expected Go to be an embedded language, and so its got serious problems... > We never expected Go to be an embedded language and so its got serious problems...
-- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799) -- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799)
+3 -46
View File
@@ -255,18 +255,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path() result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
} }
// Strip default initializers for -X globals from the type info before
// building SSA. This prevents go/ssa from emitting init stores for them,
// so that makeGlobalsModule can supply the correct values at final link
// time without any runtime init overwriting them. The -X values themselves
// are kept out of the per-package build cache; only the variable names
// appear in the cache key.
for _, pkg := range lprogram.Sorted() {
for name := range globalValues[pkg.Pkg.Path()] {
pkg.StripVarInitializer(name)
}
}
// Create the *ssa.Program. This does not yet build the entire SSA of the // Create the *ssa.Program. This does not yet build the entire SSA of the
// program so it's pretty fast and doesn't need to be parallelized. // program so it's pretty fast and doesn't need to be parallelized.
program := lprogram.LoadSSA() program := lprogram.LoadSSA()
@@ -489,7 +477,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if pkgInit.IsNil() { if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path()) panic("init not found for " + pkg.Pkg.Path())
} }
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA()) err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
if err != nil { if err != nil {
return err return err
} }
@@ -558,23 +546,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil { if err != nil {
return fmt.Errorf("failed to load bitcode file: %w", err) return fmt.Errorf("failed to load bitcode file: %w", err)
} }
// Resolve duplicate function definitions before linking.
// This can happen when a newer Go version adds a function
// body in a standard library package that was previously
// just a declaration provided by //go:linkname from the
// runtime. In that case, keep the existing (runtime)
// definition by weakening the new one's linkage so the
// LLVM linker discards it in favor of the existing one.
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
if fn.IsDeclaration() {
continue
}
existing := mod.NamedFunction(fn.Name())
if existing.IsNil() || existing.IsDeclaration() {
continue
}
fn.SetLinkage(llvm.LinkOnceODRLinkage)
}
err = llvm.LinkModules(mod, pkgMod) err = llvm.LinkModules(mod, pkgMod)
if err != nil { if err != nil {
return fmt.Errorf("failed to link module: %w", err) return fmt.Errorf("failed to link module: %w", err)
@@ -1076,7 +1047,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil { if err != nil {
return result, err return result, err
} }
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp32c6", "esp8266": case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp8266":
// Special format for the ESP family of chips (parsed by the ROM // Special format for the ESP family of chips (parsed by the ROM
// bootloader). // bootloader).
result.Binary = filepath.Join(tmpdir, "main"+outext) result.Binary = filepath.Join(tmpdir, "main"+outext)
@@ -1208,7 +1179,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
// needed to convert a program to its final form. Some transformations are not // needed to convert a program to its final form. Some transformations are not
// optional and must be run as the compiler expects them to run. // optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error { func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
err := interp.Run(mod, config.Options.InterpTimeout, config.Options.InterpMaxLoopIterations, config.DumpSSA()) err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
if err != nil { if err != nil {
return err return err
} }
@@ -1352,14 +1323,6 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
} }
baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize() baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize()
// Account for the bytes that tinygo_swapTask pushes onto the goroutine stack
// on every context switch. The static analysis correctly traces Go calls,
// but it cannot see into the assembly-level register push.
var contextSwitchOverhead uint64
if swapFuncs, ok := functions["tinygo_swapTask"]; ok && len(swapFuncs) == 1 {
contextSwitchOverhead = swapFuncs[0].FrameSize
}
sizes := make(map[string]functionStackSize) sizes := make(map[string]functionStackSize)
// Add the reset handler function, for convenience. The reset handler runs // Add the reset handler function, for convenience. The reset handler runs
@@ -1408,12 +1371,6 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
// overflow will occur even before the goroutine is started. // overflow will occur even before the goroutine is started.
stackSize = baseStackSize stackSize = baseStackSize
} }
if stackSizeType == stacksize.Bounded {
// Add the overhead of context switching. This is needed because the
// context switch (tinygo_swapTask) pushes callee-saved registers
// onto the current stack, which is not seen by the static analysis.
stackSize += contextSwitchOverhead
}
sizes[name] = functionStackSize{ sizes[name] = functionStackSize{
stackSize: stackSize, stackSize: stackSize,
stackSizeType: stackSizeType, stackSizeType: stackSizeType,
-1
View File
@@ -28,7 +28,6 @@ func TestClangAttributes(t *testing.T) {
"cortex-m4", "cortex-m4",
"cortex-m7", "cortex-m7",
"esp32c3", "esp32c3",
"esp32c6",
"esp32s3", "esp32s3",
"fe310", "fe310",
"gameboy-advance", "gameboy-advance",
+1 -1
View File
@@ -107,7 +107,7 @@ struct AssemblerInvocation {
EmitDwarfUnwindType EmitDwarfUnwind; EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries. // Whether to emit compact-unwind for non-canonical entries.
// Note: maybe overridden by other constraints. // Note: maybe overriden by other constraints.
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
unsigned EmitCompactUnwindNonCanonical : 1; unsigned EmitCompactUnwindNonCanonical : 1;
+2 -2
View File
@@ -25,8 +25,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
} }
// Version range supported by TinyGo. // Version range supported by TinyGo.
const minorMin = 24 // when updating the min version, also update .github/workflows/compat.yml const minorMin = 19
const minorMax = 26 const minorMax = 25
// Check that we support this Go toolchain version. // Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion() gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
+3 -15
View File
@@ -100,24 +100,12 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
chip_id := map[string]uint16{ chip_id := map[string]uint16{
"esp32": 0x0000, "esp32": 0x0000,
"esp32c3": 0x0005, "esp32c3": 0x0005,
"esp32c6": 0x000d,
"esp32s3": 0x0009, "esp32s3": 0x0009,
}[chip] }[chip]
// SPI flash speed/size byte (byte 3 of header):
// Upper nibble = flash size, lower nibble = flash frequency.
// The espflasher auto-detects and patches the flash size (upper nibble),
// but the frequency (lower nibble) must be correct per chip.
spiSpeedSize := map[string]uint8{
"esp32": 0x1f, // 80MHz=0x0F, 2MB=0x10
"esp32c3": 0x1f, // 80MHz=0x0F, 2MB=0x10
"esp32c6": 0x10, // 80MHz=0x00, 2MB=0x10 (C6 uses different freq encoding)
"esp32s3": 0x1f, // 80MHz=0x0F, 2MB=0x10
}[chip]
// Image header. // Image header.
switch chip { switch chip {
case "esp32", "esp32c3", "esp32s3", "esp32c6": case "esp32", "esp32c3", "esp32s3":
// Header format: // Header format:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71 // https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
// Note: not adding a SHA256 hash as the binary is modified by // Note: not adding a SHA256 hash as the binary is modified by
@@ -138,8 +126,8 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
}{ }{
magic: 0xE9, magic: 0xE9,
segment_count: byte(len(segments)), segment_count: byte(len(segments)),
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
spi_speed_size: spiSpeedSize, spi_speed_size: 0x1f, // ESP_IMAGE_SPI_SPEED_80M, ESP_IMAGE_FLASH_SIZE_2MB
entry_addr: uint32(inf.Entry), entry_addr: uint32(inf.Entry),
wp_pin: 0xEE, // disable WP pin wp_pin: 0xEE, // disable WP pin
chip_id: chip_id, chip_id: chip_id,
+3 -17
View File
@@ -167,9 +167,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// double. // double.
args = append(args, "-mdouble=64") args = append(args, "-mdouble=64")
case "riscv32": case "riscv32":
args = append(args, "-march="+riscvMarch(config, "rv32imac"), "-fforce-enable-int128") args = append(args, "-march=rv32imac", "-fforce-enable-int128")
case "riscv64": case "riscv64":
args = append(args, "-march="+riscvMarch(config, "rv64gc")) args = append(args, "-march=rv64gc")
case "mips": case "mips":
args = append(args, "-fno-pic") args = append(args, "-fno-pic")
} }
@@ -218,7 +218,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
return err return err
} }
// Store this archive in the cache. // Store this archive in the cache.
return robustRename(f.Name(), archiveFilePath) return os.Rename(f.Name(), archiveFilePath)
}, },
} }
@@ -298,17 +298,3 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
once.Do(unlock) once.Do(unlock)
}, nil }, nil
} }
// riscvMarch returns the -march value for RISC-V library compilation.
// It extracts the value from the target's cflags if present, otherwise
// falls back to the provided default. This ensures libraries are compiled
// with the correct ISA extensions for each target (e.g. rv32imc for
// ESP32-C3 which lacks the atomic extension).
func riscvMarch(config *compileopts.Config, defaultMarch string) string {
for _, flag := range config.Target.CFlags {
if strings.HasPrefix(flag, "-march=") {
return flag[len("-march="):]
}
}
return defaultMarch
}
-9
View File
@@ -1,9 +0,0 @@
//go:build !windows
package builder
import "os"
func robustRename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}
-44
View File
@@ -1,44 +0,0 @@
package builder
import (
"errors"
"math/rand"
"os"
"syscall"
"time"
)
const robustRenameTimeout = 2 * time.Second
func robustRename(oldpath, newpath string) error {
var bestErr error
start := time.Now()
nextSleep := time.Millisecond
for {
err := os.Rename(oldpath, newpath)
if err == nil || !isEphemeralRenameError(err) {
return err
}
if bestErr == nil {
bestErr = err
}
if d := time.Since(start) + nextSleep; d >= robustRenameTimeout {
return bestErr
}
time.Sleep(nextSleep)
nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
}
}
func isEphemeralRenameError(err error) bool {
var errno syscall.Errno
if errors.As(err, &errno) {
switch errno {
case syscall.Errno(2), // ERROR_FILE_NOT_FOUND
syscall.Errno(5), // ERROR_ACCESS_DENIED
syscall.Errno(32): // ERROR_SHARING_VIOLATION
return true
}
}
return false
}
+3 -13
View File
@@ -501,9 +501,8 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
Align: section.Addralign, Align: section.Addralign,
Type: memoryStack, Type: memoryStack,
}) })
} else if section.Flags&elf.SHF_WRITE != 0 { } else {
// Regular .bss section. Zero-initialized RAM is always // Regular .bss section.
// writable, so require SHF_WRITE here.
sections = append(sections, memorySection{ sections = append(sections, memorySection{
Address: section.Addr, Address: section.Addr,
Size: section.Size, Size: section.Size,
@@ -511,11 +510,6 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
Type: memoryBSS, Type: memoryBSS,
}) })
} }
// Other (non-writable) SHT_NOBITS sections are address-space
// placeholders that occupy no RAM, such as the ESP linker
// script's .irom_dummy / .rodata_dummy sections which reserve
// the flash-mapped XIP virtual address ranges. They must not be
// counted as bss/RAM usage.
} else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_EXECINSTR != 0 { } else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_EXECINSTR != 0 {
// .text // .text
sections = append(sections, memorySection{ sections = append(sections, memorySection{
@@ -960,11 +954,7 @@ func findPackagePath(path string, packagePathMap map[string]string) (packagePath
libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator)) libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator))
parts := strings.SplitN(libPath, string(os.PathSeparator), 2) parts := strings.SplitN(libPath, string(os.PathSeparator), 2)
packagePath = "C " + parts[0] packagePath = "C " + parts[0]
if len(parts) > 1 { filename = parts[1]
filename = parts[1]
} else {
filename = parts[0]
}
} else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) { } else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) {
packagePath = "C compiler-rt" packagePath = "C compiler-rt"
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator)) filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
+4 -4
View File
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test. // This is a small number of very diverse targets that we want to test.
tests := []sizeTest{ tests := []sizeTest{
// microcontrollers // microcontrollers
{"hifive1b", "examples/echo", 3699, 297, 0, 2252}, {"hifive1b", "examples/echo", 3668, 280, 0, 2244},
{"microbit", "examples/serial", 2736, 356, 8, 2248}, {"microbit", "examples/serial", 2694, 342, 8, 2248},
{"wioterminal", "examples/pininterrupt", 7960, 1652, 132, 7480}, {"wioterminal", "examples/pininterrupt", 6837, 1491, 120, 6888},
// TODO: also check wasm. Right now this is difficult, because // TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the // wasm binaries are run through wasm-opt and therefore the
@@ -99,7 +99,7 @@ func TestSizeFull(t *testing.T) {
t.Fatal("could not read program size:", err) t.Fatal("could not read program size:", err)
} }
for _, pkg := range sizes.sortedPackageNames() { for _, pkg := range sizes.sortedPackageNames() {
if pkg == "(padding)" || pkg == "(unknown)" || pkg == "Go types" { if pkg == "(padding)" || pkg == "(unknown)" {
// TODO: correctly attribute all unknown binary size. // TODO: correctly attribute all unknown binary size.
continue continue
} }
+1 -1
View File
@@ -28,7 +28,7 @@ func RunTool(tool string, args ...string) error {
var cflag *C.char var cflag *C.char
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag))) buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
defer C.free(buf) defer C.free(buf)
cflags := unsafe.Slice((**C.char)(buf), len(args)) cflags := (*[1 << 10]*C.char)(unsafe.Pointer(buf))[:len(args):len(args)]
for i, flag := range args { for i, flag := range args {
cflag := C.CString(flag) cflag := C.CString(flag)
cflags[i] = cflag cflags[i] = cflag
+2 -8
View File
@@ -121,19 +121,13 @@ func parseLLDErrors(text string) error {
if matches != nil { if matches != nil {
parsedError = true parsedError = true
line, _ := strconv.Atoi(matches[3]) line, _ := strconv.Atoi(matches[3])
msg := "linker could not find symbol " + symbolName // TODO: detect common mistakes like -gc=none?
switch symbolName {
case "runtime.alloc":
msg = "object allocated on the heap with -gc=none"
case "runtime.alloc_noheap":
msg = "object allocated on the heap in //go:noheap function"
}
linkErrors = append(linkErrors, scanner.Error{ linkErrors = append(linkErrors, scanner.Error{
Pos: token.Position{ Pos: token.Position{
Filename: matches[2], Filename: matches[2],
Line: line, Line: line,
}, },
Msg: msg, Msg: "linker could not find symbol " + symbolName,
}) })
} }
} }
+22
View File
@@ -26,6 +26,10 @@ import (
"golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/astutil"
) )
// Function that's only defined in Go 1.22.
var setASTFileFields = func(f *ast.File, start, end token.Pos) {
}
// cgoPackage holds all CGo-related information of a package. // cgoPackage holds all CGo-related information of a package.
type cgoPackage struct { type cgoPackage struct {
generated *ast.File generated *ast.File
@@ -650,6 +654,7 @@ func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
X: &ast.Ident{ X: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "union", Name: "union",
Obj: nil,
}, },
Sel: &ast.Ident{ Sel: &ast.Ident{
NamePos: pos, NamePos: pos,
@@ -703,6 +708,7 @@ func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
X: &ast.Ident{ X: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: typeName, Name: typeName,
Obj: nil,
}, },
}, },
}, },
@@ -758,6 +764,7 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
X: &ast.Ident{ X: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "s", Name: "s",
Obj: nil,
}, },
Sel: &ast.Ident{ Sel: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
@@ -804,6 +811,11 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
{ {
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "s", Name: "s",
Obj: &ast.Object{
Kind: ast.Var,
Name: "s",
Decl: nil,
},
}, },
}, },
Type: &ast.StarExpr{ Type: &ast.StarExpr{
@@ -811,6 +823,7 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
X: &ast.Ident{ X: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: typeName, Name: typeName,
Obj: nil,
}, },
}, },
}, },
@@ -868,6 +881,7 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
X: &ast.Ident{ X: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "s", Name: "s",
Obj: nil,
}, },
Sel: &ast.Ident{ Sel: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
@@ -950,6 +964,11 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
{ {
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "s", Name: "s",
Obj: &ast.Object{
Kind: ast.Var,
Name: "s",
Decl: nil,
},
}, },
}, },
Type: &ast.StarExpr{ Type: &ast.StarExpr{
@@ -957,6 +976,7 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
X: &ast.Ident{ X: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: typeName, Name: typeName,
Obj: nil,
}, },
}, },
}, },
@@ -977,6 +997,7 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
{ {
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "value", Name: "value",
Obj: nil,
}, },
}, },
Type: bitfield.field.Type, Type: bitfield.field.Type,
@@ -994,6 +1015,7 @@ func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string
X: &ast.Ident{ X: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
Name: "s", Name: "s",
Obj: nil,
}, },
Sel: &ast.Ident{ Sel: &ast.Ident{
NamePos: bitfield.pos, NamePos: bitfield.pos,
+17
View File
@@ -0,0 +1,17 @@
//go:build go1.22
package cgo
// Code specifically for Go 1.22.
import (
"go/ast"
"go/token"
)
func init() {
setASTFileFields = func(f *ast.File, start, end token.Pos) {
f.FileStart = start
f.FileEnd = end
}
}
+63 -5
View File
@@ -130,7 +130,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
// convert Go slice of strings to C array of strings. // convert Go slice of strings to C array of strings.
cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0)))) cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0))))
defer C.free(cmdargsC) defer C.free(cmdargsC)
cmdargs := unsafe.Slice((**C.char)(cmdargsC), len(cflags)) cmdargs := (*[1 << 16]*C.char)(cmdargsC)
for i, cflag := range cflags { for i, cflag := range cflags {
s := C.CString(cflag) s := C.CString(cflag)
cmdargs[i] = s cmdargs[i] = s
@@ -190,7 +190,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
// Sanity check. This should (hopefully) never trigger. // Sanity check. This should (hopefully) never trigger.
panic("libclang: file contents was not loaded") panic("libclang: file contents was not loaded")
} }
data := unsafe.Slice((*byte)(unsafe.Pointer(rawData)), size) data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
// Hash the contents if it isn't hashed yet. // Hash the contents if it isn't hashed yet.
if _, ok := f.visitedFiles[path]; !ok { if _, ok := f.visitedFiles[path]; !ok {
@@ -217,6 +217,10 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
case C.CXCursor_FunctionDecl: case C.CXCursor_FunctionDecl:
cursorType := C.tinygo_clang_getCursorType(c) cursorType := C.tinygo_clang_getCursorType(c)
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c)) numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
obj := &ast.Object{
Kind: ast.Fun,
Name: "_Cgo_" + name,
}
exportName := name exportName := name
localName := name localName := name
var stringSignature string var stringSignature string
@@ -254,6 +258,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + localName, Name: "_Cgo_" + localName,
Obj: obj,
}, },
Type: &ast.FuncType{ Type: &ast.FuncType{
Func: pos, Func: pos,
@@ -290,6 +295,11 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
{ {
NamePos: pos, NamePos: pos,
Name: argName, Name: argName,
Obj: &ast.Object{
Kind: ast.Var,
Name: argName,
Decl: decl,
},
}, },
}, },
Type: f.makeDecayingASTType(argType, pos), Type: f.makeDecayingASTType(argType, pos),
@@ -305,6 +315,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
}, },
} }
} }
obj.Decl = decl
return decl, stringSignature return decl, stringSignature
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl: case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
typ := f.makeASTRecordType(c, pos) typ := f.makeASTRecordType(c, pos)
@@ -314,27 +325,39 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
// Convert to a single-field struct type. // Convert to a single-field struct type.
typeExpr = f.makeUnionField(typ) typeExpr = f.makeUnionField(typ)
} }
obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
typeSpec := &ast.TypeSpec{ typeSpec := &ast.TypeSpec{
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: typ.pos, NamePos: typ.pos,
Name: typeName, Name: typeName,
Obj: obj,
}, },
Type: typeExpr, Type: typeExpr,
} }
obj.Decl = typeSpec
return typeSpec, typ return typeSpec, typ
case C.CXCursor_TypedefDecl: case C.CXCursor_TypedefDecl:
typeName := "_Cgo_" + name typeName := "_Cgo_" + name
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c) underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
typeSpec := &ast.TypeSpec{ typeSpec := &ast.TypeSpec{
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: typeName, Name: typeName,
Obj: obj,
}, },
Type: f.makeASTType(underlyingType, pos), Type: f.makeASTType(underlyingType, pos),
} }
if underlyingType.kind != C.CXType_Enum { if underlyingType.kind != C.CXType_Enum {
typeSpec.Assign = pos typeSpec.Assign = pos
} }
obj.Decl = typeSpec
return typeSpec, nil return typeSpec, nil
case C.CXCursor_VarDecl: case C.CXCursor_VarDecl:
cursorType := C.tinygo_clang_getCursorType(c) cursorType := C.tinygo_clang_getCursorType(c)
@@ -353,13 +376,19 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
}, },
}, },
} }
obj := &ast.Object{
Kind: ast.Var,
Name: "_Cgo_" + name,
}
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "_Cgo_" + name,
Obj: obj,
}}, }},
Type: typeExpr, Type: typeExpr,
} }
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec) gen.Specs = append(gen.Specs, valueSpec)
return gen, nil return gen, nil
case C.CXCursor_MacroDefinition: case C.CXCursor_MacroDefinition:
@@ -376,16 +405,26 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
Lparen: token.NoPos, Lparen: token.NoPos,
Rparen: token.NoPos, Rparen: token.NoPos,
} }
obj := &ast.Object{
Kind: ast.Con,
Name: "_Cgo_" + name,
}
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "_Cgo_" + name,
Obj: obj,
}}, }},
Values: []ast.Expr{expr}, Values: []ast.Expr{expr},
} }
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec) gen.Specs = append(gen.Specs, valueSpec)
return gen, nil return gen, nil
case C.CXCursor_EnumDecl: case C.CXCursor_EnumDecl:
obj := &ast.Object{
Kind: ast.Typ,
Name: "_Cgo_" + name,
}
underlying := C.tinygo_clang_getEnumDeclIntegerType(c) underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
// TODO: gc's CGo implementation uses types such as `uint32` for enums // TODO: gc's CGo implementation uses types such as `uint32` for enums
// instead of types such as C.int, which are used here. // instead of types such as C.int, which are used here.
@@ -393,10 +432,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "_Cgo_" + name,
Obj: obj,
}, },
Assign: pos, Assign: pos,
Type: f.makeASTType(underlying, pos), Type: f.makeASTType(underlying, pos),
} }
obj.Decl = typeSpec
return typeSpec, nil return typeSpec, nil
case C.CXCursor_EnumConstantDecl: case C.CXCursor_EnumConstantDecl:
value := C.tinygo_clang_getEnumConstantDeclValue(c) value := C.tinygo_clang_getEnumConstantDeclValue(c)
@@ -411,13 +452,19 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
Lparen: token.NoPos, Lparen: token.NoPos,
Rparen: token.NoPos, Rparen: token.NoPos,
} }
obj := &ast.Object{
Kind: ast.Con,
Name: "_Cgo_" + name,
}
valueSpec := &ast.ValueSpec{ valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{ Names: []*ast.Ident{{
NamePos: pos, NamePos: pos,
Name: "_Cgo_" + name, Name: "_Cgo_" + name,
Obj: obj,
}}, }},
Values: []ast.Expr{expr}, Values: []ast.Expr{expr},
} }
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec) gen.Specs = append(gen.Specs, valueSpec)
return gen, nil return gen, nil
default: default:
@@ -577,7 +624,7 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
// now by reading the file from libclang. // now by reading the file from libclang.
var size C.size_t var size C.size_t
sourcePtr := C.clang_getFileContents(tu, file, &size) sourcePtr := C.clang_getFileContents(tu, file, &size)
source := unsafe.Slice((*byte)(unsafe.Pointer(sourcePtr)), size) source := ((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[:size:size]
lines := []int{0} lines := []int{0}
for i := 0; i < len(source)-1; i++ { for i := 0; i < len(source)-1; i++ {
if source[i] == '\n' { if source[i] == '\n' {
@@ -592,8 +639,7 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
Package: f.Pos(0), Package: f.Pos(0),
Name: ast.NewIdent(p.packageName), Name: ast.NewIdent(p.packageName),
} }
astFile.FileStart = f.Pos(0) setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
astFile.FileEnd = f.Pos(int(size))
p.cgoFiles = append(p.cgoFiles, astFile) p.cgoFiles = append(p.cgoFiles, astFile)
} }
positionFile := p.tokenFiles[filename] positionFile := p.tokenFiles[filename]
@@ -910,16 +956,22 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
} }
// Construct an *ast.TypeSpec for this type. // Construct an *ast.TypeSpec for this type.
obj := &ast.Object{
Kind: ast.Typ,
Name: name,
}
spec := &ast.TypeSpec{ spec := &ast.TypeSpec{
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: name, Name: name,
Obj: obj,
}, },
Type: &ast.Ident{ Type: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: goName, Name: goName,
}, },
} }
obj.Decl = spec
return spec return spec
} }
@@ -1052,6 +1104,7 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
pos: prevField.Names[0].NamePos, pos: prevField.Names[0].NamePos,
}) })
prevField.Names[0].Name = bitfieldName prevField.Names[0].Name = bitfieldName
prevField.Names[0].Obj.Name = bitfieldName
} }
prevBitfield := &(*bitfieldList)[len(*bitfieldList)-1] prevBitfield := &(*bitfieldList)[len(*bitfieldList)-1]
prevBitfield.endBit = bitfieldOffset prevBitfield.endBit = bitfieldOffset
@@ -1068,6 +1121,11 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
{ {
NamePos: pos, NamePos: pos,
Name: name, Name: name,
Obj: &ast.Object{
Kind: ast.Var,
Name: name,
Decl: field,
},
}, },
} }
fieldList.List = append(fieldList.List, field) fieldList.List = append(fieldList.List, field)
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo package cgo
/* /*
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include -I/usr/lib64/llvm19/include #cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include #cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include
#cgo freebsd CFLAGS: -I/usr/local/llvm19/include #cgo freebsd CFLAGS: -I/usr/local/llvm19/include
+1 -1
View File
@@ -3,7 +3,7 @@
package cgo package cgo
/* /*
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include -I/usr/lib64/llvm20/include #cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include #cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
#cgo freebsd CFLAGS: -I/usr/local/llvm20/include #cgo freebsd CFLAGS: -I/usr/local/llvm20/include
-1
View File
@@ -78,7 +78,6 @@ var validCompilerFlags = []*regexp.Regexp{
re(`-f(no-)?(pic|PIC|pie|PIE)`), re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?plt`), re(`-f(no-)?plt`),
re(`-f(no-)?rtti`), re(`-f(no-)?rtti`),
re(`-f(no-)?short-enums`),
re(`-f(no-)?split-stack`), re(`-f(no-)?split-stack`),
re(`-f(no-)?stack-(.+)`), re(`-f(no-)?stack-(.+)`),
re(`-f(no-)?strict-aliasing`), re(`-f(no-)?strict-aliasing`),
+2 -2
View File
@@ -536,10 +536,10 @@ func (c *Config) Programmer() (method, openocdInterface string) {
case "": case "":
// No configuration supplied. // No configuration supplied.
return c.Target.FlashMethod, c.Target.OpenOCDInterface return c.Target.FlashMethod, c.Target.OpenOCDInterface
case "openocd", "msd", "command", "adb": case "openocd", "msd", "command":
// The -programmer flag only specifies the flash method. // The -programmer flag only specifies the flash method.
return c.Options.Programmer, c.Target.OpenOCDInterface return c.Options.Programmer, c.Target.OpenOCDInterface
case "bmp", "probe-rs": case "bmp":
// The -programmer flag only specifies the flash method. // The -programmer flag only specifies the flash method.
return c.Options.Programmer, "" return c.Options.Programmer, ""
default: default:
+39 -41
View File
@@ -21,47 +21,45 @@ var (
// usually passed from the command line, but can also be passed in environment // usually passed from the command line, but can also be passed in environment
// variables for example. // variables for example.
type Options struct { type Options struct {
GOOS string // environment variable GOOS string // environment variable
GOARCH string // environment variable GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm) GOARM string // environment variable (only used with GOARCH=arm)
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle) GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
Directory string // working dir, leave it unset to use the current working dir Directory string // working dir, leave it unset to use the current working dir
Target string Target string
BuildMode string // -buildmode flag BuildMode string // -buildmode flag
Opt string Opt string
GC string GC string
PanicStrategy string PanicStrategy string
Scheduler string Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined) StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string Serial string
Work bool // -work flag to print temporary build directory Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration InterpTimeout time.Duration
InterpMaxLoopIterations int PrintIR bool
PrintIR bool DumpSSA bool
DumpSSA bool VerifyIR bool
VerifyIR bool SkipDWARF bool
SkipDWARF bool PrintCommands func(cmd string, args ...string) `json:"-"`
PrintCommands func(cmd string, args ...string) `json:"-"` Semaphore chan struct{} `json:"-"` // -p flag controls cap
Semaphore chan struct{} `json:"-"` // -p flag controls cap Debug bool
Debug bool Nobounds bool
Nobounds bool PrintSizes string
PrintSizes string PrintAllocs *regexp.Regexp // regexp string
PrintAllocs *regexp.Regexp // regexp string PrintStacks bool
PrintAllocsCover bool // emit allocs in go coverage tool format Tags []string
PrintStacks bool GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
Tags []string TestConfig TestConfig
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value Programmer string
TestConfig TestConfig OpenOCDCommands []string
Programmer string LLVMFeatures string
OpenOCDCommands []string Monitor bool
LLVMFeatures string BaudRate int
Monitor bool Timeout time.Duration
BaudRate int WITPackage string // pass through to wasm-tools component embed invocation
Timeout time.Duration WITWorld string // pass through to wasm-tools component embed -w option
WITPackage string // pass through to wasm-tools component embed invocation ExtLDFlags []string
WITWorld string // pass through to wasm-tools component embed -w option GoCompatibility bool // enable to check for Go version compatibility
ExtLDFlags []string
GoCompatibility bool // enable to check for Go version compatibility
} }
// Verify performs a validation on the given options, raising an error if options are not valid. // Verify performs a validation on the given options, raising an error if options are not valid.
-22
View File
@@ -24,7 +24,6 @@ import (
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json // https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct { type TargetSpec struct {
Inherits []string `json:"inherits,omitempty"` Inherits []string `json:"inherits,omitempty"`
InheritableOnly bool `json:"inheritable-only"` // this target is only meant to be inherited from, not used directly
Triple string `json:"llvm-target,omitempty"` Triple string `json:"llvm-target,omitempty"`
CPU string `json:"cpu,omitempty"` CPU string `json:"cpu,omitempty"`
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
@@ -64,10 +63,6 @@ type TargetSpec struct {
OpenOCDCommands []string `json:"openocd-commands,omitempty"` OpenOCDCommands []string `json:"openocd-commands,omitempty"`
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device,omitempty"` JLinkDevice string `json:"jlink-device,omitempty"`
ADBPreCommands []string `json:"adb-pre-commands,omitempty"`
ADBPushRemote string `json:"adb-push-remote,omitempty"`
ADBPostCommands []string `json:"adb-post-commands,omitempty"`
ProbeRSChip string `json:"probe-rs-chip,omitempty"`
CodeModel string `json:"code-model,omitempty"` CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"` RelocationModel string `json:"relocation-model,omitempty"`
WITPackage string `json:"wit-package,omitempty"` WITPackage string `json:"wit-package,omitempty"`
@@ -153,11 +148,6 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
// resolveInherits loads inherited targets, recursively. // resolveInherits loads inherited targets, recursively.
func (spec *TargetSpec) resolveInherits() error { func (spec *TargetSpec) resolveInherits() error {
// Save InheritableOnly before resolving, since it must not propagate
// from parent to child (a board target should not become inheritable-only
// just because its parent processor target is).
inheritableOnly := spec.InheritableOnly
// First create a new spec with all the inherited properties. // First create a new spec with all the inherited properties.
newSpec := &TargetSpec{} newSpec := &TargetSpec{}
for _, name := range spec.Inherits { for _, name := range spec.Inherits {
@@ -183,9 +173,6 @@ func (spec *TargetSpec) resolveInherits() error {
} }
*spec = *newSpec *spec = *newSpec
// Restore InheritableOnly from the original spec, not from parents.
spec.InheritableOnly = inheritableOnly
return nil return nil
} }
@@ -252,17 +239,10 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
continue continue
} }
path := filepath.Join(dir, entry.Name()) path := filepath.Join(dir, entry.Name())
spec, err := LoadTarget(&Options{Target: path}) spec, err := LoadTarget(&Options{Target: path})
if err != nil { if err != nil {
return nil, fmt.Errorf("could not list target: %w", err) return nil, fmt.Errorf("could not list target: %w", err)
} }
if spec.InheritableOnly {
// Skip targets that are only meant to be inherited from, not used directly.
continue
}
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" { if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like // This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json). // a parent target (such as targets/cortex-m.json).
@@ -485,8 +465,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
"--no-insert-timestamp", "--no-insert-timestamp",
"--no-dynamicbase", "--no-dynamicbase",
) )
spec.ExtraFiles = append(spec.ExtraFiles,
"src/runtime/runtime_windows.c")
case "wasm", "wasip1", "wasip2": case "wasm", "wasip1", "wasip2":
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS) return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
default: default:
-31
View File
@@ -23,37 +23,6 @@ func TestLoadTarget(t *testing.T) {
} }
} }
func TestGetTargetSpecs_InheritableOnlyTargetsExcluded(t *testing.T) {
specs, err := GetTargetSpecs()
if err != nil {
t.Fatal("GetTargetSpecs failed:", err)
}
// Inheritable-only processor-level targets should not appear in the listing.
inheritableOnlyTargets := []string{"esp32", "esp32c3", "esp32s3", "esp8266", "rp2040", "rp2350", "rp2350b"}
for _, name := range inheritableOnlyTargets {
if _, ok := specs[name]; ok {
t.Errorf("inheritable-only target %q should not appear in GetTargetSpecs", name)
}
}
// Board targets that inherit from inheritable-only targets should still appear.
boardTargets := []string{"esp32-coreboard-v2", "pico"}
for _, name := range boardTargets {
if _, ok := specs[name]; !ok {
t.Errorf("board target %q should appear in GetTargetSpecs", name)
}
}
}
func TestLoadTarget_InheritableOnlyTargetStillLoadable(t *testing.T) {
// Inheritable-only targets should still be loadable directly (for building).
_, err := LoadTarget(&Options{Target: "esp32"})
if err != nil {
t.Errorf("LoadTarget should still load inheritable-only target esp32: %v", err)
}
}
func TestOverrideProperties(t *testing.T) { func TestOverrideProperties(t *testing.T) {
baseAutoStackSize := true baseAutoStackSize := true
base := &TargetSpec{ base := &TargetSpec{
+8 -21
View File
@@ -241,35 +241,22 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
} }
} }
faultBlock := b.getRuntimeAssertBlock(blockPrefix, assertFunc) // Put the fault block at the end of the function and the next block at the
// current insert position.
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
nextBlock := b.insertBasicBlock(blockPrefix + ".next") nextBlock := b.insertBasicBlock(blockPrefix + ".next")
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block. // Now branch to the out-of-bounds or the regular block.
b.CreateCondBr(assert, faultBlock, nextBlock) b.CreateCondBr(assert, faultBlock, nextBlock)
// Ok: assert didn't trigger so continue normally. // Fail: the assert triggered so panic.
b.SetInsertPointAtEnd(nextBlock) b.SetInsertPointAtEnd(faultBlock)
}
func (b *builder) getRuntimeAssertBlock(blockPrefix, assertFunc string) llvm.BasicBlock {
if b.runtimeAssertBlocks == nil {
b.runtimeAssertBlocks = make(map[string]llvm.BasicBlock)
}
if block := b.runtimeAssertBlocks[assertFunc]; !block.IsNil() {
return block
}
savedBlock := b.GetInsertBlock()
block := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
b.runtimeAssertBlocks[assertFunc] = block
b.SetInsertPointAtEnd(block)
if b.hasDeferFrame() {
b.createFaultCheckpoint()
}
b.createRuntimeCall(assertFunc, nil, "") b.createRuntimeCall(assertFunc, nil, "")
b.CreateUnreachable() b.CreateUnreachable()
b.SetInsertPointAtEnd(savedBlock)
return block // Ok: assert didn't trigger so continue normally.
b.SetInsertPointAtEnd(nextBlock)
} }
// extendInteger extends the value to at least targetType using a zero or sign // extendInteger extends the value to at least targetType using a zero or sign
+2 -2
View File
@@ -48,7 +48,7 @@ func (b *builder) createChanSend(instr *ssa.Send) {
channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op") channelOpAlloca, channelOpAllocaSize := b.createTemporaryAlloca(channelOp, "chan.op")
// Do the send. // Do the send.
b.createRuntimeInvoke("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "") b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelOpAlloca}, "")
// End the lifetime of the allocas. // End the lifetime of the allocas.
// This also works around a bug in CoroSplit, at least in LLVM 8: // This also works around a bug in CoroSplit, at least in LLVM 8:
@@ -101,7 +101,7 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
// createChanClose closes the given channel. // createChanClose closes the given channel.
func (b *builder) createChanClose(ch llvm.Value) { func (b *builder) createChanClose(ch llvm.Value) {
b.createRuntimeInvoke("chanClose", []llvm.Value{ch}, "") b.createRuntimeCall("chanClose", []llvm.Value{ch}, "")
} }
// createSelect emits all IR necessary for a select statements. That's a // createSelect emits all IR necessary for a select statements. That's a
+9 -36
View File
@@ -92,7 +92,6 @@ type compilerContext struct {
pkg *types.Package pkg *types.Package
packageDir string // directory for this package packageDir string // directory for this package
runtimePkg *types.Package runtimePkg *types.Package
localTypeNames typeutil.Map // *types.Named (synthetic local from generic instantiation) -> string
} }
// newCompilerContext returns a new compiler context ready for use, most // newCompilerContext returns a new compiler context ready for use, most
@@ -177,9 +176,6 @@ type builder struct {
deferBuiltinFuncs map[ssa.Value]deferBuiltin deferBuiltinFuncs map[ssa.Value]deferBuiltin
runDefersBlock []llvm.BasicBlock runDefersBlock []llvm.BasicBlock
afterDefersBlock []llvm.BasicBlock afterDefersBlock []llvm.BasicBlock
runtimeAssertBlocks map[string]llvm.BasicBlock
interfaceAssertBlock llvm.BasicBlock
} }
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder { func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
@@ -304,11 +300,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Convert AST to SSA. // Convert AST to SSA.
ssaPkg.Build() ssaPkg.Build()
// Assign names to function-local named types before compiling the
// package, so that types declared in different functions (or in
// different instantiations of a generic function) do not collide.
c.scanLocalTypes(ssaPkg)
// Initialize debug information. // Initialize debug information.
if c.Debug { if c.Debug {
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{ c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
@@ -323,6 +314,9 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Load comments such as //go:extern on globals. // Load comments such as //go:extern on globals.
c.loadASTComments(pkg) c.loadASTComments(pkg)
// Predeclare the runtime.alloc function, which is used by the wordpack
// functionality.
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
if c.NeedsStackObjects { if c.NeedsStackObjects {
// Predeclare trackPointer, which is used everywhere we use runtime.alloc. // Predeclare trackPointer, which is used everywhere we use runtime.alloc.
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function)) c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
@@ -868,9 +862,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
} }
// Create the function definition. // Create the function definition.
b := newBuilder(c, irbuilder, member) b := newBuilder(c, irbuilder, member)
if ok := b.defineMathOp(); ok { if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok {
// The body of this function (if there is one) is ignored and // The body of this function (if there is one) is ignored and
// replaced with a LLVM intrinsic call. // replaced with a LLVM intrinsic call.
b.defineMathOp()
continue continue
} }
if ok := b.defineMathBitsIntrinsic(); ok { if ok := b.defineMathBitsIntrinsic(); ok {
@@ -878,10 +873,6 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
// with a LLVM intrinsic. // with a LLVM intrinsic.
continue continue
} }
if ok := b.defineCryptoIntrinsic(); ok {
// Body of this function was replaced
continue
}
if member.Blocks == nil { if member.Blocks == nil {
// Try to define this as an intrinsic function. // Try to define this as an intrinsic function.
b.defineIntrinsicFunction() b.defineIntrinsicFunction()
@@ -1354,15 +1345,6 @@ func (b *builder) createFunctionStart(intrinsic bool) {
// diagnostic. // diagnostic.
func (b *builder) createFunction() { func (b *builder) createFunction() {
b.createFunctionStart(false) b.createFunctionStart(false)
// createFunctionStart returns early (leaving blockInfo unset) when it hits
// an error such as a redeclared symbol. Don't plow into the block loop and
// panic on an empty blockInfo — the error was already recorded.
if b.blockInfo == nil {
// TINYGO-DEBUG: surface the redeclaration collision.
fmt.Printf("TINYGO-DEBUG skipping fn (redeclared/errored): %s pkg=%s\n",
b.fn.RelString(nil), b.fn.Pkg.Pkg.Path())
return
}
// Fill blocks with instructions. // Fill blocks with instructions.
for _, block := range b.fn.DomPreorder() { for _, block := range b.fn.DomPreorder() {
@@ -1902,12 +1884,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
// not of the current function. // not of the current function.
useParentFrame = 1 useParentFrame = 1
} }
// Prevent inlining of functions that call recover(), matching the
// Go compiler's behavior. If this function were inlined into a
// deferred function, recover() would incorrectly succeed because
// the inlined code runs in the deferred function's context.
noinline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0)
b.llvmFn.AddFunctionAttr(noinline)
return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil
case "ssa:wrapnilchk": case "ssa:wrapnilchk":
// TODO: do an actual nil check? // TODO: do an actual nil check?
@@ -2000,14 +1976,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.emitSV64Call(instr.Args, getPos(instr)) return b.emitSV64Call(instr.Args, getPos(instr))
case strings.HasPrefix(name, "(device/riscv.CSR)."): case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr) return b.emitCSROperation(instr)
case (strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall")) && name != "syscall.SyscallN": case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
if b.GOOS != "darwin" { if b.GOOS != "darwin" {
return b.createSyscall(instr) return b.createSyscall(instr)
} }
case name == "syscall.syscalln":
if b.GOOS == "windows" {
return b.createSyscalln(instr)
}
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"): case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
return b.createRawSyscallNoError(instr) return b.createRawSyscallNoError(instr)
case name == "runtime.supportsRecover": case name == "runtime.supportsRecover":
@@ -2196,8 +2168,9 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
} }
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
layoutValue := b.createObjectLayout(typ, expr.Pos()) layoutValue := b.createObjectLayout(typ, expr.Pos())
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
align := b.targetData.ABITypeAlignment(typ) align := b.targetData.ABITypeAlignment(typ)
buf := b.createAlloc(sizeValue, layoutValue, align, expr.Comment) buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
return buf, nil return buf, nil
} else { } else {
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment) buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
@@ -2427,7 +2400,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
} }
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap") sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos()) layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
slicePtr := b.createAlloc(sliceSize, layoutValue, 0, "makeslice.buf") slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign))) slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
// Extend or truncate if necessary. This is safe as we've already done // Extend or truncate if necessary. This is safe as we've already done
-1
View File
@@ -50,7 +50,6 @@ func TestCompiler(t *testing.T) {
{"channel.go", "", ""}, {"channel.go", "", ""},
{"gc.go", "", ""}, {"gc.go", "", ""},
{"zeromap.go", "", ""}, {"zeromap.go", "", ""},
{"generics.go", "", ""},
} }
if goMinor >= 20 { if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""}) tests = append(tests, testCase{"go1.20.go", "", ""})
+5 -22
View File
@@ -60,6 +60,10 @@ func (b *builder) deferInitFunc() {
b.deferExprFuncs = make(map[ssa.Value]int) b.deferExprFuncs = make(map[ssa.Value]int)
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin) b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
// Create defer list pointer.
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
if b.hasDeferFrame() { if b.hasDeferFrame() {
// Set up the defer frame with the current stack pointer. // Set up the defer frame with the current stack pointer.
// This assumes that the stack pointer doesn't move outside of the // This assumes that the stack pointer doesn't move outside of the
@@ -69,22 +73,12 @@ func (b *builder) deferInitFunc() {
// in the setjmp-like inline assembly. // in the setjmp-like inline assembly.
deferFrameType := b.getLLVMRuntimeType("deferFrame") deferFrameType := b.getLLVMRuntimeType("deferFrame")
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf") b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
// The field index must match the DeferPtr field in runtime.deferFrame,
// defined in src/runtime/panic.go.
b.deferPtr = b.CreateInBoundsGEP(deferFrameType, b.deferFrame, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 6, false), // DeferPtr field
}, "deferPtr")
stackPointer := b.readStackPointer() stackPointer := b.readStackPointer()
b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "") b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "")
// Create the landing pad block, which is where control transfers after // Create the landing pad block, which is where control transfers after
// a panic. // a panic.
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad") b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad")
} else {
// Create defer list pointer.
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
} }
} }
@@ -243,17 +237,6 @@ func (b *builder) createInvokeCheckpoint() {
b.currentBlockInfo.exit = continueBB b.currentBlockInfo.exit = continueBB
} }
// createFaultCheckpoint is like createInvokeCheckpoint but for use in fault
// blocks (e.g., bounds check failures). Unlike createInvokeCheckpoint, it does
// not update currentBlockInfo.exit because the fault block is a dead-end that
// does not participate in phi node resolution.
func (b *builder) createFaultCheckpoint() {
isZero := b.createCheckpoint(b.deferFrame)
continueBB := b.insertBasicBlock("")
b.CreateCondBr(isZero, continueBB, b.landingpad)
b.SetInsertPointAtEnd(continueBB)
}
// isInLoop checks if there is a path from the current block to itself. // isInLoop checks if there is a path from the current block to itself.
// Use Tarjan's strongly connected components algorithm to search for cycles. // Use Tarjan's strongly connected components algorithm to search for cycles.
// A one-node SCC is a cycle iff there is an edge from the node to itself. // A one-node SCC is a cycle iff there is an edge from the node to itself.
@@ -505,7 +488,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
size := b.targetData.TypeAllocSize(deferredCallType) size := b.targetData.TypeAllocSize(deferredCallType)
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
nilPtr := llvm.ConstNull(b.dataPtrType) nilPtr := llvm.ConstNull(b.dataPtrType)
alloca = b.createAlloc(sizeValue, nilPtr, 0, "defer.alloc.call") alloca = b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
} }
if b.NeedsStackObjects { if b.NeedsStackObjects {
b.trackPointer(alloca) b.trackPointer(alloca)
-26
View File
@@ -10,32 +10,6 @@ import (
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
// Heap-allocate a buffer of the given size. This will typically call
// runtime.alloc.
func (b *builder) createAlloc(sizeValue, layoutValue llvm.Value, align int, comment string) llvm.Value {
// Normally allocate using "runtime.alloc", but use "runtime.alloc_noheap"
// if the //go:noheap pragma is used.
allocFunc := "alloc"
if b.info.noheap {
allocFunc = "alloc_noheap"
}
// Allocs that don't allocate anything can return an architecture-specific
// sentinel value.
if !sizeValue.IsAConstantInt().IsNil() && sizeValue.ZExtValue() == 0 {
allocFunc = "alloc_zero"
}
// Make the runtime call.
call := b.createRuntimeCall(allocFunc, []llvm.Value{sizeValue, layoutValue}, comment)
if align != 0 {
// TODO: make sure all callsites set the correct alignment.
call.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
}
return call
}
// trackExpr inserts pointer tracking intrinsics for the GC if the expression is // trackExpr inserts pointer tracking intrinsics for the GC if the expression is
// one of the expressions that need this. // one of the expressions that need this.
func (b *builder) trackExpr(expr ssa.Value, value llvm.Value) { func (b *builder) trackExpr(expr ssa.Value, value llvm.Value) {
+80 -478
View File
@@ -10,8 +10,6 @@ import (
"fmt" "fmt"
"go/token" "go/token"
"go/types" "go/types"
"path/filepath"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -19,12 +17,6 @@ import (
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
// numMethodHasMethodSet is a flag in bit 15 of the numMethod field (uint16) in
// Named, Pointer, and Struct type descriptors. When set, an inline method set
// is present in the type descriptor. Must match the constant in
// src/internal/reflectlite/type.go.
const numMethodHasMethodSet = 0x8000
// Type kinds for basic types. // Type kinds for basic types.
// They must match the constants for the Kind type in src/reflect/type.go. // They must match the constants for the Kind type in src/reflect/type.go.
var basicTypes = [...]uint8{ var basicTypes = [...]uint8{
@@ -166,7 +158,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
} }
} }
typeCodeName, isLocal := c.getTypeCodeName(typ) typeCodeName, isLocal := getTypeCodeName(typ)
globalName := "reflect/types.type:" + typeCodeName globalName := "reflect/types.type:" + typeCodeName
var global llvm.Value var global llvm.Value
if isLocal { if isLocal {
@@ -191,16 +183,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
typeFieldTypes := []*types.Var{ typeFieldTypes := []*types.Var{
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]), types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
} }
// Compute the method set value for types that support methods.
var methods []*types.Func
for i := 0; i < ms.Len(); i++ {
methods = append(methods, ms.At(i).Obj().(*types.Func))
}
methodSetType := types.NewStruct([]*types.Var{
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
types.NewVar(token.NoPos, nil, "methods", types.NewArray(types.Typ[types.UnsafePointer], int64(len(methods)))),
}, nil)
methodSetValue := c.getMethodSetValue(methods)
switch typ := typ.(type) { switch typ := typ.(type) {
case *types.Basic: case *types.Basic:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
@@ -217,13 +199,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "underlying", 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, "pkgpath", types.Typ[types.UnsafePointer]),
)
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))), 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:
@@ -243,11 +218,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
) )
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
case *types.Array: case *types.Array:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
@@ -272,16 +242,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))), types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
) )
if len(methods) > 0 {
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "methods", methodSetType),
)
}
case *types.Interface: case *types.Interface:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "methods", methodSetType),
) )
// TODO: methods
case *types.Signature: case *types.Signature:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
@@ -327,24 +292,14 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
pkgname = pkg.Name() pkgname = pkg.Name()
} }
pkgPathPtr := c.pkgPathPtr(pkgpath) pkgPathPtr := c.pkgPathPtr(pkgpath)
namedNumMethods := uint64(numMethods)
if namedNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on named type " + name)
}
if len(methods) > 0 {
namedNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), namedNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Underlying()), // underlying c.getTypeCode(typ.Underlying()), // underlying
pkgPathPtr, // pkgpath pointer pkgPathPtr, // pkgpath pointer
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
} }
if len(methods) > 0 { metabyte |= 1 << 5 // "named" flag
typeFields = append(typeFields, methodSetValue) // methods
}
typeFields = append(typeFields, c.ctx.ConstString(pkgname+"."+name+"\x00", false)) // name
metabyte |= 1 << 5 // "named" flag
case *types.Chan: case *types.Chan:
var dir reflectChanDir var dir reflectChanDir
switch typ.Dir() { switch typ.Dir() {
@@ -368,20 +323,10 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
c.getTypeCode(typ.Elem()), // elementType c.getTypeCode(typ.Elem()), // elementType
} }
case *types.Pointer: case *types.Pointer:
ptrNumMethods := uint64(numMethods)
if ptrNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on pointer type")
}
if len(methods) > 0 {
ptrNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), ptrNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(typ.Elem()), c.getTypeCode(typ.Elem()),
} }
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Array: case *types.Array:
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
@@ -408,16 +353,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
llvmStructType := c.getLLVMType(typ) llvmStructType := c.getLLVMType(typ)
size := c.targetData.TypeStoreSize(llvmStructType) size := c.targetData.TypeStoreSize(llvmStructType)
structNumMethods := uint64(numMethods)
if structNumMethods&numMethodHasMethodSet != 0 {
panic("numMethods overflow: too many exported methods on struct type")
}
if len(methods) > 0 {
structNumMethods |= numMethodHasMethodSet
}
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), structNumMethods, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
pkgPathPtr, pkgPathPtr,
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
@@ -469,14 +407,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
})) }))
} }
typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields)) typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
if len(methods) > 0 {
typeFields = append(typeFields, methodSetValue)
}
case *types.Interface: case *types.Interface:
typeFields = []llvm.Value{ typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
c.getTypeCode(types.NewPointer(typ)), // TODO: methods
methodSetValue,
}
case *types.Signature: case *types.Signature:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
// TODO: params, return values, etc // TODO: params, return values, etc
@@ -581,50 +514,20 @@ var basicTypeNames = [...]string{
// getTypeCodeName returns a name for this type that can be used in the // getTypeCodeName returns a name for this type that can be used in the
// interface lowering pass to assign type codes as expected by the reflect // interface lowering pass to assign type codes as expected by the reflect
// package. See getTypeCodeNum. // package. See getTypeCodeNum.
// func getTypeCodeName(t types.Type) (string, bool) {
// isLocal is true when the type is declared inside a function body.
// Such types need a per-declaration (or per instantiation) suffix
// because their printed names are not unique.
//
// Ordinary function-local types (TypeName.Parent() != nil) are
// disambiguated lazily from their declaration position: every
// declaration in the package has a distinct (file, line, column)
// triple, and the position is taken un-//line-adjusted so it is
// stable across builds. Such types are only nameable inside their
// declaring package, so the name does not need to agree with anything
// computed in another package.
//
// Synthetic locals (TypeName.Parent() == nil), produced by generic
// instantiation, are pre-registered by scanLocalTypes because their
// names must agree across packages that materialize the same instance.
func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bool) {
switch t := types.Unalias(t).(type) { switch t := types.Unalias(t).(type) {
case *types.Named: case *types.Named:
tn := t.Obj() if t.Obj().Parent() != t.Obj().Pkg().Scope() {
if tn.Pkg() == nil || tn.Parent() == tn.Pkg().Scope() { return "named:" + t.String() + "$local", true
// Package-scope or builtin: the printed name is unique.
return "named:" + t.String(), false
} }
if tn.Parent() != nil { return "named:" + t.String(), false
// Ordinary function-local type. Use the un-//line-adjusted
// declaration position as the disambiguator.
pos := c.program.Fset.PositionFor(tn.Pos(), false)
return fmt.Sprintf("named:%s$%s:%d:%d", t.String(), filepath.Base(pos.Filename), pos.Line, pos.Column), true
}
// Synthetic local from generic instantiation: must have been
// pre-registered by scanLocalTypes.
v := c.localTypeNames.At(t)
if v == nil {
panic("compiler: synthetic local type " + tn.Name() + " was not registered by scanLocalTypes")
}
return "named:" + v.(string), true
case *types.Array: case *types.Array:
s, isLocal := c.getTypeCodeName(t.Elem()) s, isLocal := getTypeCodeName(t.Elem())
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + s, isLocal return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + s, isLocal
case *types.Basic: case *types.Basic:
return "basic:" + basicTypeNames[t.Kind()], false return "basic:" + basicTypeNames[t.Kind()], false
case *types.Chan: case *types.Chan:
s, isLocal := c.getTypeCodeName(t.Elem()) s, isLocal := getTypeCodeName(t.Elem())
var dir string var dir string
switch t.Dir() { switch t.Dir() {
case types.SendOnly: case types.SendOnly:
@@ -644,7 +547,7 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
if !token.IsExported(name) { if !token.IsExported(name) {
name = t.Method(i).Pkg().Path() + "." + name name = t.Method(i).Pkg().Path() + "." + name
} }
s, local := c.getTypeCodeName(t.Method(i).Type()) s, local := getTypeCodeName(t.Method(i).Type())
if local { if local {
isLocal = true isLocal = true
} }
@@ -652,17 +555,17 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
} }
return "interface:" + "{" + strings.Join(methods, ",") + "}", isLocal return "interface:" + "{" + strings.Join(methods, ",") + "}", isLocal
case *types.Map: case *types.Map:
keyType, keyLocal := c.getTypeCodeName(t.Key()) keyType, keyLocal := getTypeCodeName(t.Key())
elemType, elemLocal := c.getTypeCodeName(t.Elem()) elemType, elemLocal := getTypeCodeName(t.Elem())
return "map:" + "{" + keyType + "," + elemType + "}", keyLocal || elemLocal return "map:" + "{" + keyType + "," + elemType + "}", keyLocal || elemLocal
case *types.Pointer: case *types.Pointer:
s, isLocal := c.getTypeCodeName(t.Elem()) s, isLocal := getTypeCodeName(t.Elem())
return "pointer:" + s, isLocal return "pointer:" + s, isLocal
case *types.Signature: case *types.Signature:
isLocal := false isLocal := false
params := make([]string, t.Params().Len()) params := make([]string, t.Params().Len())
for i := 0; i < t.Params().Len(); i++ { for i := 0; i < t.Params().Len(); i++ {
s, local := c.getTypeCodeName(t.Params().At(i).Type()) s, local := getTypeCodeName(t.Params().At(i).Type())
if local { if local {
isLocal = true isLocal = true
} }
@@ -670,7 +573,7 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
} }
results := make([]string, t.Results().Len()) results := make([]string, t.Results().Len())
for i := 0; i < t.Results().Len(); i++ { for i := 0; i < t.Results().Len(); i++ {
s, local := c.getTypeCodeName(t.Results().At(i).Type()) s, local := getTypeCodeName(t.Results().At(i).Type())
if local { if local {
isLocal = true isLocal = true
} }
@@ -678,7 +581,7 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
} }
return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}", isLocal return "func:" + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}", isLocal
case *types.Slice: case *types.Slice:
s, isLocal := c.getTypeCodeName(t.Elem()) s, isLocal := getTypeCodeName(t.Elem())
return "slice:" + s, isLocal return "slice:" + s, isLocal
case *types.Struct: case *types.Struct:
elems := make([]string, t.NumFields()) elems := make([]string, t.NumFields())
@@ -688,7 +591,7 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
if t.Field(i).Embedded() { if t.Field(i).Embedded() {
embedded = "#" embedded = "#"
} }
s, local := c.getTypeCodeName(t.Field(i).Type()) s, local := getTypeCodeName(t.Field(i).Type())
if local { if local {
isLocal = true isLocal = true
} }
@@ -703,232 +606,6 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo
} }
} }
// scanLocalTypes assigns names to every synthetic *types.TypeName
// (TypeName.Parent() == nil) reachable from this package and stores
// them in c.localTypeNames.
//
// Synthetic TypeNames are produced by generic instantiation: two
// instantiations of the same generic function (e.g. F[int] and
// F[string]) produce TypeNames with the same printed name and the
// same source position, so each is named with the enclosing
// instance's RelString as prefix. RelString encodes the type
// arguments, matching Go's runtime behavior, where F[int].Inner and
// F[string].Inner are distinct types even when Inner does not mention
// the type parameter.
//
// A given instance may be materialized by several packages (the body
// of F[int] is compiled in every package that calls F[int]); its
// reflect/types.type:* global has LinkOnceODRLinkage and is merged by
// name at link time. The chosen name therefore depends only on
// intrinsic SSA properties (RelString and the raw token.Pos used as a
// sort key), so any package compiling the same instance produces the
// same identifier.
//
// Ordinary function-local TypeNames (TypeName.Parent() != nil) are
// not handled here: they are nameable only inside their declaring
// package, and getTypeCodeName derives a stable per-declaration name
// for them directly from their source position.
func (c *compilerContext) scanLocalTypes(ssaPkg *ssa.Package) {
// Locate every generic instance reachable from this package
// (including instances declared in imported packages and any
// function reached through an instance subtree).
var instances []*ssa.Function
seen := map[*ssa.Function]struct{}{}
var walk func(fn *ssa.Function, inInstance bool)
walk = func(fn *ssa.Function, inInstance bool) {
if fn == nil {
return
}
if _, ok := seen[fn]; ok {
return
}
// fn belongs to an instance subtree if it is itself an
// instantiation or if we reached it from one.
//
// len(TypeArgs()) is used instead of fn.Origin() because
// Origin() may call Build() on fn's declaring package, which
// would defeat per-package compilation.
isInstanceRoot := len(fn.TypeArgs()) > 0
if !isInstanceRoot && !inInstance && fn.Pkg != ssaPkg {
return
}
if fn.Blocks == nil && fn.AnonFuncs == nil {
return
}
seen[fn] = struct{}{}
isInInstance := inInstance || isInstanceRoot
if isInInstance {
instances = append(instances, fn)
}
for _, anon := range fn.AnonFuncs {
walk(anon, isInInstance)
}
var ops [10]*ssa.Value
for _, b := range fn.Blocks {
for _, instr := range b.Instrs {
for _, op := range instr.Operands(ops[:0]) {
if op == nil || *op == nil {
continue
}
if callee, ok := (*op).(*ssa.Function); ok {
walk(callee, isInInstance)
}
}
}
}
}
for _, member := range ssaPkg.Members {
switch m := member.(type) {
case *ssa.Function:
walk(m, false)
case *ssa.Type:
mset := c.program.MethodSets.MethodSet(m.Type())
for i := 0; i < mset.Len(); i++ {
walk(c.program.MethodValue(mset.At(i)), false)
}
pmset := c.program.MethodSets.MethodSet(types.NewPointer(m.Type()))
for i := 0; i < pmset.Len(); i++ {
walk(c.program.MethodValue(pmset.At(i)), false)
}
}
}
// Registration is first-writer-wins (a synthetic TypeName may be
// reachable from several instances), so visit instances in a
// deterministic order. Pos() is a defensive tiebreaker.
sort.Slice(instances, func(i, j int) bool {
ri, rj := instances[i].RelString(nil), instances[j].RelString(nil)
if ri != rj {
return ri < rj
}
return instances[i].Pos() < instances[j].Pos()
})
for _, fn := range instances {
c.registerSyntheticLocalTypes(fn)
}
}
// registerSyntheticLocalTypes walks every type reachable from fn's
// body and records each synthetic *types.Named (TypeName.Parent() ==
// nil) in c.localTypeNames. Each is named with fn.RelString as the
// owning function plus a per-function counter assigned in source
// order.
//
// First-writer-wins: a *types.Named already present in
// c.localTypeNames is left alone, so a synthetic type reachable from
// several instances keeps the name assigned by the first (in
// scanLocalTypes' deterministic order).
func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) {
var found []*types.Named
seen := map[types.Type]struct{}{}
var visit func(t types.Type)
visit = func(t types.Type) {
if t == nil {
return
}
if _, ok := seen[t]; ok {
return
}
seen[t] = struct{}{}
switch t := t.(type) {
case *types.Alias:
visit(types.Unalias(t))
case *types.Named:
tn := t.Obj()
if tn.Pkg() != nil && tn.Parent() == nil {
if c.localTypeNames.At(t) == nil {
// Reserve the slot so later calls within this
// scanLocalTypes invocation skip it; the final
// name is filled in after sorting, before any
// getTypeCodeName lookups happen.
c.localTypeNames.Set(t, "")
found = append(found, t)
}
}
targs := t.TypeArgs()
for i := 0; i < targs.Len(); i++ {
visit(targs.At(i))
}
visit(t.Underlying())
case *types.Pointer:
visit(t.Elem())
case *types.Slice:
visit(t.Elem())
case *types.Array:
visit(t.Elem())
case *types.Chan:
visit(t.Elem())
case *types.Map:
visit(t.Key())
visit(t.Elem())
case *types.Struct:
for i := 0; i < t.NumFields(); i++ {
visit(t.Field(i).Type())
}
case *types.Signature:
if p := t.Params(); p != nil {
for i := 0; i < p.Len(); i++ {
visit(p.At(i).Type())
}
}
if r := t.Results(); r != nil {
for i := 0; i < r.Len(); i++ {
visit(r.At(i).Type())
}
}
case *types.Tuple:
for i := 0; i < t.Len(); i++ {
visit(t.At(i).Type())
}
case *types.Interface:
// A synthetic local type can be reachable only through a
// local interface's method signature, so descend into
// them. getTypeCodeName encodes those signatures into
// the interface's identifier, and the seen map breaks
// cycles formed by methods that mention the interface
// itself.
for i := 0; i < t.NumMethods(); i++ {
visit(t.Method(i).Type())
}
}
}
for _, p := range fn.Params {
visit(p.Type())
}
for _, fv := range fn.FreeVars {
visit(fv.Type())
}
for _, l := range fn.Locals {
visit(l.Type())
}
var ops [10]*ssa.Value
for _, b := range fn.Blocks {
for _, instr := range b.Instrs {
if v, ok := instr.(ssa.Value); ok {
visit(v.Type())
}
for _, op := range instr.Operands(ops[:0]) {
if op != nil && *op != nil {
visit((*op).Type())
}
}
}
}
if len(found) == 0 {
return
}
// Sort by raw token.Pos: this gives a total order on declarations
// that is stable across builds and unaffected by //line directives
// (which only adjust the human-facing position from Fset.Position).
sort.Slice(found, func(i, j int) bool {
return found[i].Obj().Pos() < found[j].Obj().Pos()
})
enclosing := fn.RelString(nil)
for i, named := range found {
c.localTypeNames.Set(named, fmt.Sprintf("%s.%s$%d", enclosing, named.Obj().Name(), i))
}
}
// getTypeMethodSet returns a reference (GEP) to a global method set. This // getTypeMethodSet returns a reference (GEP) to a global method set. This
// method set should be unreferenced after the interface lowering pass. // method set should be unreferenced after the interface lowering pass.
func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value { func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
@@ -1019,14 +696,20 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
// This type assertion always succeeds, so we can just set commaOk to true. // This type assertion always succeeds, so we can just set commaOk to true.
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true) commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
} else { } else {
// Type assert on an interface type with methods. // Type assert on interface type with methods.
// Create a call to a declared-but-not-defined function that will // This is a call to an interface type assert function.
// be lowered by the interface lowering pass into a type-ID // The interface lowering pass will define this function by filling it
// comparison chain. // with a type switch over all concrete types that implement this
commaOk = b.createInterfaceTypeAssert(intf, actualTypeNum) // interface, and returning whether it's one of the matched types.
// This is very different from how interface asserts are implemented in
// the main Go compiler, where the runtime checks whether the type
// implements each method of the interface. See:
// https://research.swtch.com/interfaces
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
} }
} else { } else {
name, _ := b.getTypeCodeName(expr.AssertedType) name, _ := getTypeCodeName(expr.AssertedType)
globalName := "reflect/types.typeid:" + name globalName := "reflect/types.typeid:" + name
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName) assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() { if assertedTypeCodeGlobal.IsNil() {
@@ -1053,68 +736,43 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
prevBlock := b.GetInsertBlock() prevBlock := b.GetInsertBlock()
okBlock := b.insertBasicBlock("typeassert.ok") okBlock := b.insertBasicBlock("typeassert.ok")
nextBlock := b.insertBasicBlock("typeassert.next")
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
b.CreateCondBr(commaOk, okBlock, nextBlock)
// Retrieve the value from the interface if the type assert was
// successful.
b.SetInsertPointAtEnd(okBlock)
var valueOk llvm.Value
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
// Type assert on interface type. Easy: just return the same
// interface value.
valueOk = itf
} else {
// Type assert on concrete type. Extract the underlying type from
// the interface (but only after checking it matches).
valueOk = b.extractValueFromInterface(itf, assertedType)
}
b.CreateBr(nextBlock)
// Continue after the if statement.
b.SetInsertPointAtEnd(nextBlock)
phi := b.CreatePHI(assertedType, "typeassert.value")
phi.AddIncoming([]llvm.Value{llvm.ConstNull(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
if expr.CommaOk { if expr.CommaOk {
nextBlock := b.insertBasicBlock("typeassert.next")
b.currentBlockInfo.exit = nextBlock
b.CreateCondBr(commaOk, okBlock, nextBlock)
// Retrieve the value from the interface if the type assert was
// successful.
b.SetInsertPointAtEnd(okBlock)
var valueOk llvm.Value
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
// Type assert on interface type. Easy: just return the same
// interface value.
valueOk = itf
} else {
// Type assert on concrete type. Extract the underlying type from
// the interface (but only after checking it matches).
valueOk = b.extractValueFromInterface(itf, assertedType)
}
b.CreateBr(nextBlock)
// Continue after the if statement.
b.SetInsertPointAtEnd(nextBlock)
phi := b.CreatePHI(assertedType, "typeassert.value")
phi.AddIncoming([]llvm.Value{llvm.ConstNull(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
tuple := b.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(b.ctx.Int1Type())}, false) // create empty tuple tuple := b.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(b.ctx.Int1Type())}, false) // create empty tuple
tuple = b.CreateInsertValue(tuple, phi, 0, "") // insert value tuple = b.CreateInsertValue(tuple, phi, 0, "") // insert value
tuple = b.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean tuple = b.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
return tuple return tuple
} else { } else {
// Type assert without comma-ok. If it fails, panic. // This is kind of dirty as the branch above becomes mostly useless,
faultBlock := b.getInterfaceAssertBlock() // but hopefully this gets optimized away.
b.currentBlockInfo.exit = okBlock b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "")
b.CreateCondBr(commaOk, okBlock, faultBlock) return phi
// OK: extract the value from the interface.
b.SetInsertPointAtEnd(okBlock)
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
return itf
}
return b.extractValueFromInterface(itf, assertedType)
} }
} }
func (b *builder) getInterfaceAssertBlock() llvm.BasicBlock {
if !b.interfaceAssertBlock.IsNil() {
return b.interfaceAssertBlock
}
savedBlock := b.GetInsertBlock()
block := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.throw")
b.interfaceAssertBlock = block
b.SetInsertPointAtEnd(block)
if b.hasDeferFrame() {
b.createFaultCheckpoint()
}
b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
b.CreateUnreachable()
b.SetInsertPointAtEnd(savedBlock)
return block
}
// getMethodsString returns a string to be used in the "tinygo-methods" string // getMethodsString returns a string to be used in the "tinygo-methods" string
// attribute for interface functions. // attribute for interface functions.
func (c *compilerContext) getMethodsString(itf *types.Interface) string { func (c *compilerContext) getMethodsString(itf *types.Interface) string {
@@ -1125,65 +783,27 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
return strings.Join(methods, "; ") return strings.Join(methods, "; ")
} }
// getMethodSetValue creates the method set struct value for a list of methods. // getInterfaceImplementsFunc returns a declared function that works as a type
// The struct contains a length and a sorted array of method signature pointers. // switch. The interface lowering pass will define this function.
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value { func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
// Create a sorted list of method signature global names. s, _ := getTypeCodeName(assertedType.Underlying())
type methodRef struct { fnName := s + ".$typeassert"
name string llvmFn := c.mod.NamedFunction(fnName)
value llvm.Value if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
c.addStandardDeclaredAttributes(llvmFn)
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
} }
var refs []methodRef return llvmFn
for _, method := range methods {
name := method.Name()
if !token.IsExported(name) {
name = method.Pkg().Path() + "." + name
}
s, _ := c.getTypeCodeName(method.Type())
globalName := "reflect/types.signature:" + name + ":" + s
value := c.mod.NamedGlobal(globalName)
if value.IsNil() {
value = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
value.SetInitializer(llvm.ConstNull(c.ctx.Int8Type()))
value.SetGlobalConstant(true)
value.SetLinkage(llvm.LinkOnceODRLinkage)
value.SetAlignment(1)
if c.Debug {
file := c.getDIFile("<Go type>")
diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{
Name: globalName,
File: file,
Line: 1,
Type: c.getDIType(types.Typ[types.Uint8]),
LocalToUnit: false,
Expr: c.dibuilder.CreateExpression(nil),
AlignInBits: 8,
})
value.AddMetadata(0, diglobal)
}
}
refs = append(refs, methodRef{globalName, value})
}
sort.Slice(refs, func(i, j int) bool {
return refs[i].name < refs[j].name
})
var values []llvm.Value
for _, ref := range refs {
values = append(values, ref.value)
}
return c.ctx.ConstStruct([]llvm.Value{
llvm.ConstInt(c.uintptrType, uint64(len(values)), false),
llvm.ConstArray(c.dataPtrType, values),
}, false)
} }
// getInvokeFunction returns the thunk to call the given interface method. The // getInvokeFunction returns the thunk to call the given interface method. The
// thunk is declared, not defined: it will be defined by the interface lowering // thunk is declared, not defined: it will be defined by the interface lowering
// pass. // pass.
func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value { func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
s, _ := c.getTypeCodeName(instr.Value.Type().Underlying()) s, _ := getTypeCodeName(instr.Value.Type().Underlying())
fnName := s + "." + instr.Method.Name() + "$invoke" fnName := s + "." + instr.Method.Name() + "$invoke"
llvmFn := c.mod.NamedFunction(fnName) llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() { if llvmFn.IsNil() {
@@ -1203,24 +823,6 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
return llvmFn return llvmFn
} }
// createInterfaceTypeAssert creates a call to a declared-but-not-defined
// $typeassert function for the given interface. This function will be defined
// by the interface lowering pass as a type-ID comparison chain, avoiding the
// need for runtime.typeImplementsMethodSet at compile time.
func (b *builder) createInterfaceTypeAssert(intf *types.Interface, actualType llvm.Value) llvm.Value {
s, _ := b.getTypeCodeName(intf)
fnName := s + ".$typeassert"
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
llvmFnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{b.dataPtrType}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, llvmFnType)
b.addStandardDeclaredAttributes(llvmFn)
methods := b.getMethodsString(intf)
llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("tinygo-methods", methods))
}
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{actualType}, "")
}
// getInterfaceInvokeWrapper returns a wrapper for the given method so it can be // getInterfaceInvokeWrapper returns a wrapper for the given method so it can be
// invoked from an interface. The wrapper takes in a pointer to the underlying // invoked from an interface. The wrapper takes in a pointer to the underlying
// value, dereferences or unpacks it if necessary, and calls the real method. // value, dereferences or unpacks it if necessary, and calls the real method.
+8 -59
View File
@@ -7,7 +7,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -167,22 +166,12 @@ func (b *builder) createMachineKeepAliveImpl() {
} }
var mathToLLVMMapping = map[string]string{ var mathToLLVMMapping = map[string]string{
"math.Acos": "llvm.acos.f64",
"math.Asin": "llvm.asin.f64",
"math.Atan": "llvm.atan.f64",
"math.Atan2": "llvm.atan2.f64",
"math.Ceil": "llvm.ceil.f64", "math.Ceil": "llvm.ceil.f64",
"math.Cos": "llvm.cos.f64",
"math.Cosh": "llvm.cosh.f64",
"math.Exp": "llvm.exp.f64", "math.Exp": "llvm.exp.f64",
"math.Exp2": "llvm.exp2.f64", "math.Exp2": "llvm.exp2.f64",
"math.Floor": "llvm.floor.f64", "math.Floor": "llvm.floor.f64",
"math.Log": "llvm.log.f64", "math.Log": "llvm.log.f64",
"math.Sin": "llvm.sin.f64",
"math.Sinh": "llvm.sinh.f64",
"math.Sqrt": "llvm.sqrt.f64", "math.Sqrt": "llvm.sqrt.f64",
"math.Tan": "llvm.tan.f64",
"math.Tanh": "llvm.tanh.f64",
"math.Trunc": "llvm.trunc.f64", "math.Trunc": "llvm.trunc.f64",
} }
@@ -196,40 +185,18 @@ var mathToLLVMMapping = map[string]string{
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is // float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
// beneficial on architectures where 64-bit floating point operations are (much) // beneficial on architectures where 64-bit floating point operations are (much)
// more expensive than 32-bit ones. // more expensive than 32-bit ones.
func (b *builder) defineMathOp() bool { func (b *builder) defineMathOp() {
llvmName, ok := mathToLLVMMapping[b.fn.RelString(nil)]
if !ok {
return false
}
if strings.HasSuffix(b.Triple, "-wasi") || llvmutil.Version() < 19 {
// We don't have a real libc for wasip2. Until that is fixed, we need to
// limit math intrinsics on WASI to a subset supported natively in
// WebAssembly.
// Also, since we don't know the specific libc we will target, disallow
// these for all WASI targets.
//
// We also need to limit ourselves to LLVM 19 and above for the extended
// set of math intrinsics, see:
// https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294
switch b.fn.Name() {
case "Ceil", "Exp", "Exp2", "Floor", "Log", "Sqrt", "Trunc":
default:
return false
}
}
b.createFunctionStart(true) b.createFunctionStart(true)
llvmName := mathToLLVMMapping[b.fn.RelString(nil)]
if llvmName == "" {
panic("unreachable: unknown math operation") // sanity check
}
llvmFn := b.mod.NamedFunction(llvmName) llvmFn := b.mod.NamedFunction(llvmName)
if llvmFn.IsNil() { if llvmFn.IsNil() {
// The intrinsic doesn't exist yet, so declare it. // The intrinsic doesn't exist yet, so declare it.
var llvmType llvm.Type // At the moment, all supported intrinsics have the form "double
switch b.fn.Name() { // foo(double %x)" so we can hardcode the signature here.
case "Atan2": llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
// double atan2(double %y, double %x)
llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false)
default:
// double foo(double %x)
llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
}
llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType) llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType)
} }
// Create a call to the intrinsic. // Create a call to the intrinsic.
@@ -239,24 +206,6 @@ func (b *builder) defineMathOp() bool {
} }
result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "") result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "")
b.CreateRet(result) b.CreateRet(result)
return true
}
func (b *builder) defineCryptoIntrinsic() bool {
if b.fn.Pkg.Pkg.Path() != "crypto/internal/constanttime" {
return false
}
switch b.fn.Name() {
case "boolToUint8":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
result := b.CreateZExt(param, b.ctx.Int8Type(), "")
b.CreateRet(result)
return true
}
return false
} }
// Implement most math/bits functions. // Implement most math/bits functions.
+7 -1
View File
@@ -129,7 +129,13 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
// Packed data is bigger than a pointer, so allocate it on the heap. // Packed data is bigger than a pointer, so allocate it on the heap.
sizeValue := llvm.ConstInt(b.uintptrType, size, false) sizeValue := llvm.ConstInt(b.uintptrType, size, false)
align := b.targetData.ABITypeAlignment(packedType) align := b.targetData.ABITypeAlignment(packedType)
packedAlloc := b.createAlloc(sizeValue, llvm.ConstNull(b.dataPtrType), align, "") alloc := b.mod.NamedFunction("runtime.alloc")
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
sizeValue,
llvm.ConstNull(b.dataPtrType),
llvm.Undef(b.dataPtrType), // unused context parameter
}, "")
packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
if b.NeedsStackObjects { if b.NeedsStackObjects {
b.trackPointer(packedAlloc) b.trackPointer(packedAlloc)
} }
+158 -445
View File
@@ -3,28 +3,42 @@ package compiler
// This file emits the correct map intrinsics for map operations. // This file emits the correct map intrinsics for map operations.
import ( import (
"fmt"
"go/token" "go/token"
"go/types" "go/types"
"github.com/tinygo-org/tinygo/src/tinygo"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
const hashArrayUnrollLimit = 4
// createMakeMap creates a new map object (runtime.hashmap) by allocating and // createMakeMap creates a new map object (runtime.hashmap) by allocating and
// initializing an appropriately sized object. // initializing an appropriately sized object.
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) { func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
mapType := expr.Type().Underlying().(*types.Map) mapType := expr.Type().Underlying().(*types.Map)
keyType := mapType.Key().Underlying() keyType := mapType.Key().Underlying()
llvmValueType := b.getLLVMType(mapType.Elem().Underlying()) llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
llvmKeyType := b.getLLVMType(keyType) var llvmKeyType llvm.Type
var alg uint64
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// String keys.
llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmString)
} else if hashmapIsBinaryKey(keyType) {
// Trivially comparable keys.
llvmKeyType = b.getLLVMType(keyType)
alg = uint64(tinygo.HashmapAlgorithmBinary)
} else {
// All other keys. Implemented as map[interface{}]valueType for ease of
// implementation.
llvmKeyType = b.getLLVMRuntimeType("_interface")
alg = uint64(tinygo.HashmapAlgorithmInterface)
}
keySize := b.targetData.TypeAllocSize(llvmKeyType) keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType) valueSize := b.targetData.TypeAllocSize(llvmValueType)
llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false) llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false) llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
sizeHint := llvm.ConstInt(b.uintptrType, 8, false) sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil { if expr.Reserve != nil {
sizeHint = b.getValue(expr.Reserve, getPos(expr)) sizeHint = b.getValue(expr.Reserve, getPos(expr))
var err error var err error
@@ -33,42 +47,10 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
return llvm.Value{}, err return llvm.Value{}, err
} }
} }
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
// Resolve hash and equal functions for this key type. For string and
// binary key types, reference the corresponding runtime functions
// directly. For composite types, generate type-specific functions.
var hashFn, equalFn llvm.Value
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
hashFn = b.getRuntimeFunctionValue("hashmapStringPtrHash", hashmapKeyHashSignature())
equalFn = b.getRuntimeFunctionValue("hashmapStringEqual", hashmapKeyEqualSignature())
} else if hashmapIsBinaryKey(keyType) {
hashFn = b.getRuntimeFunctionValue("hash32", hashmapKeyHashSignature())
equalFn = b.getRuntimeFunctionValue("memequal", hashmapKeyEqualSignature())
} else {
fn := b.getOrGenerateKeyHashFunc(keyType)
hashFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyHashSignature())
fn = b.getOrGenerateKeyEqualFunc(keyType)
equalFn = b.createFuncValue(fn, llvm.ConstNull(b.dataPtrType), hashmapKeyEqualSignature())
}
hashmap := b.createRuntimeCall("hashmapMakeGeneric", []llvm.Value{
llvmKeySize, llvmValueSize, sizeHint,
hashFn, equalFn,
}, "")
return hashmap, nil return hashmap, nil
} }
// getRuntimeFunctionValue returns a TinyGo function value (with nil context)
// for the named runtime function.
func (b *builder) getRuntimeFunctionValue(name string, sig *types.Signature) llvm.Value {
member := b.program.ImportedPackage("runtime").Members[name]
if member == nil {
panic("unknown runtime function: " + name)
}
_, llvmFn := b.getFunction(member.(*ssa.Function))
return b.createFuncValue(llvmFn, llvm.ConstNull(b.dataPtrType), sig)
}
// createMapLookup returns the value in a map. It calls a runtime function // createMapLookup returns the value in a map. It calls a runtime function
// depending on the map key type to load the map value and its comma-ok value. // depending on the map key type to load the map value and its comma-ok value.
func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) { func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
@@ -90,23 +72,32 @@ func (b *builder) createMapLookup(keyType, valueType types.Type, m, key llvm.Val
// Do the lookup. How it is done depends on the key type. // Do the lookup. How it is done depends on the key type.
var commaOkValue llvm.Value var commaOkValue llvm.Value
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key, mapValueAlloca, mapValueSize} params := []llvm.Value{m, key, mapValueAlloca, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "") commaOkValue = b.createRuntimeCall("hashmapStringGet", params, "")
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type: either binary-comparable or with // key can be compared with runtime.memequal
// compiler-generated hash/equal. // Store the key in an alloca, in the entry block to avoid dynamic stack
// growth.
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, mapKeyAlloca) b.CreateStore(key, mapKeyAlloca)
b.zeroUndefBytes(b.getLLVMType(keyType), mapKeyAlloca)
// Fetch the value from the hashmap.
params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize} params := []llvm.Value{m, mapKeyAlloca, mapValueAlloca, mapValueSize}
fnName := "hashmapBinaryGet" commaOkValue = b.createRuntimeCall("hashmapBinaryGet", params, "")
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericGet"
}
commaOkValue = b.createRuntimeCall(fnName, params, "")
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize) b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
} else {
// Not trivially comparable using memcmp. Make it an interface instead.
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)
}
params := []llvm.Value{m, itfKey, mapValueAlloca, mapValueSize}
commaOkValue = b.createRuntimeCall("hashmapInterfaceGet", params, "")
} }
// Load the resulting value from the hashmap. The value is set to the zero // Load the resulting value from the hashmap. The value is set to the zero
@@ -129,22 +120,29 @@ 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) { func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value") valueAlloca, valueSize := b.createTemporaryAlloca(value.Type(), "hashmap.value")
b.CreateStore(value, valueAlloca) b.CreateStore(value, valueAlloca)
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key, valueAlloca} params := []llvm.Value{m, key, valueAlloca}
b.createRuntimeInvoke("hashmapStringSet", params, "") b.createRuntimeCall("hashmapStringSet", params, "")
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type. // key can be compared with runtime.memequal
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca) b.CreateStore(key, keyAlloca)
fnName := "hashmapBinarySet" b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericSet"
}
params := []llvm.Value{m, keyAlloca, valueAlloca} params := []llvm.Value{m, keyAlloca, valueAlloca}
b.createRuntimeInvoke(fnName, params, "") b.createRuntimeCall("hashmapBinarySet", params, "")
b.emitLifetimeEnd(keyAlloca, keySize) b.emitLifetimeEnd(keyAlloca, keySize)
} else {
// Key is not trivially comparable, so compare it as an interface instead.
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)
}
params := []llvm.Value{m, itfKey, valueAlloca}
b.createRuntimeCall("hashmapInterfaceSet", params, "")
} }
b.emitLifetimeEnd(valueAlloca, valueSize) b.emitLifetimeEnd(valueAlloca, valueSize)
} }
@@ -152,24 +150,32 @@ func (b *builder) createMapUpdate(keyType types.Type, m, key, value llvm.Value,
// createMapDelete deletes a key from a map by calling the appropriate runtime // createMapDelete deletes a key from a map by calling the appropriate runtime
// function. It is the implementation of the Go delete() builtin. // 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 { func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
origKeyType := keyType
keyType = keyType.Underlying() keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 { if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string // key is a string
params := []llvm.Value{m, key} params := []llvm.Value{m, key}
b.createRuntimeCall("hashmapStringDelete", params, "") b.createRuntimeCall("hashmapStringDelete", params, "")
return nil return nil
} else { } else if hashmapIsBinaryKey(keyType) {
// Key stored at actual type.
keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key") keyAlloca, keySize := b.createTemporaryAlloca(key.Type(), "hashmap.key")
b.CreateStore(key, keyAlloca) b.CreateStore(key, keyAlloca)
fnName := "hashmapBinaryDelete" b.zeroUndefBytes(b.getLLVMType(keyType), keyAlloca)
if !hashmapIsBinaryKey(keyType) {
fnName = "hashmapGenericDelete"
}
params := []llvm.Value{m, keyAlloca} params := []llvm.Value{m, keyAlloca}
b.createRuntimeCall(fnName, params, "") b.createRuntimeCall("hashmapBinaryDelete", params, "")
b.emitLifetimeEnd(keyAlloca, keySize) b.emitLifetimeEnd(keyAlloca, keySize)
return nil return nil
} else {
// Key is not trivially comparable, so compare it as an interface
// instead.
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)
}
params := []llvm.Value{m, itfKey}
b.createRuntimeCall("hashmapInterfaceDelete", params, "")
return nil
} }
} }
@@ -189,15 +195,42 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
llvmKeyType := b.getLLVMType(keyType) llvmKeyType := b.getLLVMType(keyType)
llvmValueType := b.getLLVMType(valueType) llvmValueType := b.getLLVMType(valueType)
// All key types are now stored at their declared type (no interface wrapping). // There is a special case in which keys are stored as an interface value
// instead of the value they normally are. This happens for non-trivially
// comparable types such as float32 or some structs.
isKeyStoredAsInterface := false
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
} else {
// The key is stored as an interface value, and may or may not be an
// interface type (for example, float32 keys are stored as an interface
// value).
if _, ok := keyType.Underlying().(*types.Interface); !ok {
isKeyStoredAsInterface = true
}
}
// Determine the type of the key as stored in the map.
llvmStoredKeyType := llvmKeyType
if isKeyStoredAsInterface {
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
}
// Extract the key and value from the map. // Extract the key and value from the map.
mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key") mapKeyAlloca, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value") mapValueAlloca, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next") ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyAlloca, mapValueAlloca}, "range.next")
mapKey := b.CreateLoad(llvmKeyType, mapKeyAlloca, "") mapKey := b.CreateLoad(llvmStoredKeyType, mapKeyAlloca, "")
mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "") mapValue := b.CreateLoad(llvmValueType, mapValueAlloca, "")
if isKeyStoredAsInterface {
// The key is stored as an interface but it isn't of interface type.
// Extract the underlying value.
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
}
// End the lifetimes of the allocas, because we're done with them. // End the lifetimes of the allocas, because we're done with them.
b.emitLifetimeEnd(mapKeyAlloca, mapKeySize) b.emitLifetimeEnd(mapKeyAlloca, mapKeySize)
b.emitLifetimeEnd(mapValueAlloca, mapValueSize) b.emitLifetimeEnd(mapValueAlloca, mapValueSize)
@@ -217,9 +250,20 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
func hashmapIsBinaryKey(keyType types.Type) bool { func hashmapIsBinaryKey(keyType types.Type) bool {
switch keyType := keyType.Underlying().(type) { switch keyType := keyType.Underlying().(type) {
case *types.Basic: case *types.Basic:
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 || keyType.Kind() == types.UnsafePointer // TODO: unsafe.Pointer is also a binary key, but to support that we
// need to fix an issue with interp first (see
// https://github.com/tinygo-org/tinygo/pull/4898).
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
case *types.Pointer: case *types.Pointer:
return true return true
case *types.Struct:
for i := 0; i < keyType.NumFields(); i++ {
fieldType := keyType.Field(i).Type().Underlying()
if !hashmapIsBinaryKey(fieldType) {
return false
}
}
return true
case *types.Array: case *types.Array:
return hashmapIsBinaryKey(keyType.Elem()) return hashmapIsBinaryKey(keyType.Elem())
default: default:
@@ -227,399 +271,68 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
} }
} }
// hashmapKeyHashSignature returns the Go type signature for hashmap key hash func (b *builder) zeroUndefBytes(llvmType llvm.Type, ptr llvm.Value) error {
// functions: func(key unsafe.Pointer, size, seed uintptr) uint32 // We know that hashmapIsBinaryKey is true, so we only have to handle those types that can show up there.
func hashmapKeyHashSignature() *types.Signature { // To zero all undefined bytes, we iterate over all the fields in the type. For each element, compute the
return types.NewSignatureType(nil, nil, nil, // offset of that element. If it's Basic type, there are no internal padding bytes. For compound types, we recurse to ensure
types.NewTuple( // we handle nested types. Next, we determine if there are any padding bytes before the next
types.NewVar(token.NoPos, nil, "key", types.Typ[types.UnsafePointer]), // element and zero those as well.
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uintptr]),
types.NewVar(token.NoPos, nil, "seed", types.Typ[types.Uintptr]),
),
types.NewTuple(
types.NewVar(token.NoPos, nil, "", types.Typ[types.Uint32]),
),
false,
)
}
// hashmapKeyEqualSignature returns the Go type signature for hashmap key equal zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
// functions: func(x, y unsafe.Pointer, n uintptr) bool
func hashmapKeyEqualSignature() *types.Signature {
return types.NewSignatureType(nil, nil, nil,
types.NewTuple(
types.NewVar(token.NoPos, nil, "x", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "y", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "n", types.Typ[types.Uintptr]),
),
types.NewTuple(
types.NewVar(token.NoPos, nil, "", types.Typ[types.Bool]),
),
false,
)
}
// hashmapKeyFuncName returns a canonical name for a generated hash or equal switch llvmType.TypeKind() {
// function based on the key type's underlying structure. Named types are case llvm.IntegerTypeKind:
// replaced with their underlying types so that structurally identical key // no padding bytes
// types (e.g., struct{i1; str1} and struct{i2; str2} where both i1, i2 are return nil
// int and str1, str2 are string) share the same generated function. case llvm.PointerTypeKind:
func hashmapKeyFuncName(prefix string, keyType types.Type) string { // mo padding bytes
return prefix + "." + hashmapCanonicalTypeName(keyType) return nil
} case llvm.ArrayTypeKind:
llvmArrayType := llvmType
llvmElemType := llvmType.ElementType()
// hashmapCanonicalTypeName returns a string representation of the hash/equal for i := 0; i < llvmArrayType.ArrayLength(); i++ {
// operations needed for a type, stripping named types where the operation does idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
// not depend on the name. Pointer and channel names do not include the element elemPtr := b.CreateInBoundsGEP(llvmArrayType, ptr, []llvm.Value{zero, idx}, "")
// type because their hash/equal operations only use the pointer word.
func hashmapCanonicalTypeName(t types.Type) string { // zero any padding bytes in this element
switch t := t.Underlying().(type) { b.zeroUndefBytes(llvmElemType, elemPtr)
case *types.Basic:
return t.Name()
case *types.Pointer:
return "*"
case *types.Chan:
switch t.Dir() {
case types.SendRecv:
return "chan"
case types.SendOnly:
return "chan<-"
case types.RecvOnly:
return "<-chan"
} }
case *types.Interface:
if t.NumMethods() == 0 {
return "interface{}"
}
return t.String()
case *types.Struct:
s := "struct{"
for i := 0; i < t.NumFields(); i++ {
if i > 0 {
s += "; "
}
s += hashmapCanonicalTypeName(t.Field(i).Type())
}
return s + "}"
case *types.Array:
return fmt.Sprintf("[%d]%s", t.Len(), hashmapCanonicalTypeName(t.Elem()))
}
return t.String()
}
// getOrGenerateKeyHashFunc returns an LLVM function that computes the hash case llvm.StructTypeKind:
// of a key of the given type. The function is generated on first call and llvmStructType := llvmType
// cached in the module. numFields := llvmStructType.StructElementTypesCount()
func (b *builder) getOrGenerateKeyHashFunc(keyType types.Type) llvm.Value { llvmElementTypes := llvmStructType.StructElementTypes()
name := hashmapKeyFuncName("hashmapKeyHash", keyType)
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
return fn
}
// Create the LLVM function type: for i := 0; i < numFields; i++ {
// (key ptr, size uintptr, seed uintptr, context ptr) -> i32
fnType := llvm.FunctionType(b.ctx.Int32Type(), []llvm.Type{
b.dataPtrType, b.uintptrType, b.uintptrType, b.dataPtrType,
}, false)
fn := llvm.AddFunction(b.mod, name, fnType)
fn.SetLinkage(llvm.LinkOnceODRLinkage)
fn.SetUnnamedAddr(true)
b.addStandardAttributes(fn)
// Generate the function body.
savedBlock := b.GetInsertBlock()
defer b.SetInsertPointAtEnd(savedBlock)
entry := b.ctx.AddBasicBlock(fn, "entry")
b.SetInsertPointAtEnd(entry)
keyPtr := fn.Param(0)
seed := fn.Param(2)
llvmKeyType := b.getLLVMType(keyType)
hash := b.generateKeyHash(keyType, llvmKeyType, keyPtr, seed)
b.CreateRet(hash)
return fn
}
// getOrGenerateKeyEqualFunc returns an LLVM function that compares two keys
// of the given type for equality. The function is generated on first call
// and cached in the module.
func (b *builder) getOrGenerateKeyEqualFunc(keyType types.Type) llvm.Value {
name := hashmapKeyFuncName("hashmapKeyEqual", keyType)
if fn := b.mod.NamedFunction(name); !fn.IsNil() {
return fn
}
// Create the LLVM function type:
// (x ptr, y ptr, n uintptr, context ptr) -> i1
fnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{
b.dataPtrType, b.dataPtrType, b.uintptrType, b.dataPtrType,
}, false)
fn := llvm.AddFunction(b.mod, name, fnType)
fn.SetLinkage(llvm.LinkOnceODRLinkage)
fn.SetUnnamedAddr(true)
b.addStandardAttributes(fn)
// Generate the function body.
savedBlock := b.GetInsertBlock()
defer b.SetInsertPointAtEnd(savedBlock)
entry := b.ctx.AddBasicBlock(fn, "entry")
b.SetInsertPointAtEnd(entry)
xPtr := fn.Param(0)
yPtr := fn.Param(1)
llvmKeyType := b.getLLVMType(keyType)
result := b.generateKeyEqual(keyType, llvmKeyType, xPtr, yPtr, fn)
b.CreateRet(result)
return fn
}
// generateKeyHash generates IR that hashes a key value. Returns the i32 hash.
func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, keyPtr llvm.Value, seed llvm.Value) llvm.Value {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
if keyType.Info()&types.IsString != 0 {
// Hash the string contents. The size parameter is unused by
// hashmapStringPtrHash (it dereferences the string header to
// get the actual length), but we pass it for signature
// consistency with other hash functions.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapStringPtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
}
if keyType.Info()&types.IsFloat != 0 {
// Float hash: normalizes -0 to +0 before hashing.
if keyType.Kind() == types.Float32 {
return b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{keyPtr, seed}, "hash")
}
return b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{keyPtr, seed}, "hash")
}
if keyType.Info()&types.IsComplex != 0 {
// Complex hash: hash real and imaginary parts as floats.
if keyType.Kind() == types.Complex64 {
realPtr := keyPtr
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
llvm.ConstInt(b.uintptrType, 4, false),
}, "")
realHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{realPtr, seed}, "hash.real")
imagHash := b.createRuntimeCall("hashmapFloat32Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
return b.CreateXor(realHash, imagHash, "")
}
realPtr := keyPtr
imagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), keyPtr, []llvm.Value{
llvm.ConstInt(b.uintptrType, 8, false),
}, "")
realHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{realPtr, seed}, "hash.real")
imagHash := b.createRuntimeCall("hashmapFloat64Hash", []llvm.Value{imagPtr, seed}, "hash.imag")
return b.CreateXor(realHash, imagHash, "")
}
// Integer/boolean: hash the raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Pointer, *types.Chan:
// Pointers and channels: hash as raw pointer-sized bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Interface:
// Interface: use runtime reflection-based hash.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
case *types.Struct:
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < keyType.NumFields(); i++ {
if keyType.Field(i).Name() == "_" {
continue // blank fields are ignored in Go equality
}
fieldType := keyType.Field(i).Type()
llvmFieldType := b.getLLVMType(fieldType)
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
continue // skip zero-sized fields
}
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false) idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "") elemPtr := b.CreateInBoundsGEP(llvmStructType, ptr, []llvm.Value{zero, idx}, "")
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
hash = b.CreateXor(hash, fieldHash, "")
}
return hash
case *types.Array:
elemType := keyType.Elem()
llvmElemType := b.getLLVMType(elemType)
arrayLen := keyType.Len()
if hashmapIsBinaryKey(elemType) {
// All elements are binary-comparable; hash the entire array as raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hash32", []llvm.Value{keyPtr, size, seed}, "hash")
}
if arrayLen == 0 {
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
}
if arrayLen <= hashArrayUnrollLimit {
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < int(arrayLen); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
hash = b.CreateXor(hash, elemHash, "")
}
return hash
}
initHash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
loopEntry := b.GetInsertBlock() // zero any padding bytes in this field
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.body") llvmElemType := llvmElementTypes[i]
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "hash.array.done") b.zeroUndefBytes(llvmElemType, elemPtr)
b.CreateBr(loopBody) // zero any padding bytes before the next field, if any
b.SetInsertPointAtEnd(loopBody) offset := b.targetData.ElementOffset(llvmStructType, i)
storeSize := b.targetData.TypeStoreSize(llvmElemType)
fieldEndOffset := offset + storeSize
phiI := b.CreatePHI(b.uintptrType, "i") var nextOffset uint64
phiHash := b.CreatePHI(b.ctx.Int32Type(), "hash.acc") if i < numFields-1 {
nextOffset = b.targetData.ElementOffset(llvmStructType, i+1)
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
newHash := b.CreateXor(phiHash, elemHash, "")
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
b.CreateCondBr(cond, loopBody, loopDone)
bodyEnd := b.GetInsertBlock()
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
[]llvm.BasicBlock{loopEntry, bodyEnd})
phiHash.AddIncoming([]llvm.Value{initHash, newHash},
[]llvm.BasicBlock{loopEntry, bodyEnd})
b.SetInsertPointAtEnd(loopDone)
return newHash
default:
panic(fmt.Sprintf("unhandled key type for hash generation: %T", keyType))
}
}
// generateKeyEqual generates IR that compares two key values for equality.
// Returns an i1 result.
func (b *builder) generateKeyEqual(keyType types.Type, llvmKeyType llvm.Type, xPtr, yPtr llvm.Value, fn llvm.Value) llvm.Value {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
if keyType.Info()&types.IsString != 0 {
// Compare strings: load both string headers and compare.
xStr := b.CreateLoad(llvmKeyType, xPtr, "x.str")
yStr := b.CreateLoad(llvmKeyType, yPtr, "y.str")
return b.createRuntimeCall("stringEqual", []llvm.Value{xStr, yStr}, "eq")
}
if keyType.Info()&types.IsFloat != 0 {
// Float equality: fcmp oeq handles -0==+0 (true) and NaN==NaN (false).
xVal := b.CreateLoad(llvmKeyType, xPtr, "x.float")
yVal := b.CreateLoad(llvmKeyType, yPtr, "y.float")
return b.CreateFCmp(llvm.FloatOEQ, xVal, yVal, "eq")
}
if keyType.Info()&types.IsComplex != 0 {
// Complex equality: both real and imaginary parts must be equal.
var floatType llvm.Type
if keyType.Kind() == types.Complex64 {
floatType = b.ctx.FloatType()
} else { } else {
floatType = b.ctx.DoubleType() // Last field? Next offset is the total size of the allocate struct.
nextOffset = b.targetData.TypeAllocSize(llvmStructType)
} }
floatSize := b.targetData.TypeAllocSize(floatType)
imagOffset := llvm.ConstInt(b.uintptrType, floatSize, false) if fieldEndOffset != nextOffset {
// Real parts n := llvm.ConstInt(b.uintptrType, nextOffset-fieldEndOffset, false)
xReal := b.CreateLoad(floatType, xPtr, "x.real") llvmStoreSize := llvm.ConstInt(b.uintptrType, storeSize, false)
yReal := b.CreateLoad(floatType, yPtr, "y.real") paddingStart := b.CreateInBoundsGEP(b.ctx.Int8Type(), elemPtr, []llvm.Value{llvmStoreSize}, "")
realEq := b.CreateFCmp(llvm.FloatOEQ, xReal, yReal, "eq.real") b.createRuntimeCall("memzero", []llvm.Value{paddingStart, n}, "")
// Imaginary parts
xImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), xPtr, []llvm.Value{imagOffset}, "")
yImagPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), yPtr, []llvm.Value{imagOffset}, "")
xImag := b.CreateLoad(floatType, xImagPtr, "x.imag")
yImag := b.CreateLoad(floatType, yImagPtr, "y.imag")
imagEq := b.CreateFCmp(llvm.FloatOEQ, xImag, yImag, "eq.imag")
return b.CreateAnd(realEq, imagEq, "")
}
// Integer/boolean: compare raw bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Pointer, *types.Chan:
// Pointers and channels: compare as raw pointer-sized bytes.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Interface:
// Interface: use runtime interface equality.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("hashmapInterfaceEqual", []llvm.Value{xPtr, yPtr, size}, "eq")
case *types.Struct:
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false) // start with true
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < keyType.NumFields(); i++ {
if keyType.Field(i).Name() == "_" {
continue // blank fields are ignored in Go equality
} }
fieldType := keyType.Field(i).Type()
llvmFieldType := b.getLLVMType(fieldType)
if b.targetData.TypeAllocSize(llvmFieldType) == 0 {
continue // skip zero-sized fields
}
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
xFieldPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
yFieldPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
fieldEq := b.generateKeyEqual(fieldType, llvmFieldType, xFieldPtr, yFieldPtr, fn)
result = b.CreateAnd(result, fieldEq, "")
} }
return result
case *types.Array:
elemType := keyType.Elem()
llvmElemType := b.getLLVMType(elemType)
arrayLen := keyType.Len()
if hashmapIsBinaryKey(elemType) {
// All elements are binary-comparable; compare the entire array.
size := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(llvmKeyType), false)
return b.createRuntimeCall("memequal", []llvm.Value{xPtr, yPtr, size}, "eq")
}
if arrayLen == 0 {
return llvm.ConstInt(b.ctx.Int1Type(), 1, false)
}
if arrayLen <= hashArrayUnrollLimit {
result := llvm.ConstInt(b.ctx.Int1Type(), 1, false)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < int(arrayLen); i++ {
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, idx}, "")
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, idx}, "")
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
result = b.CreateAnd(result, elemEq, "")
}
return result
}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
loopEntry := b.GetInsertBlock()
loopBody := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.body")
loopDone := b.ctx.AddBasicBlock(loopEntry.Parent(), "eq.array.done")
b.CreateBr(loopBody)
b.SetInsertPointAtEnd(loopBody)
phiI := b.CreatePHI(b.uintptrType, "i")
xElemPtr := b.CreateInBoundsGEP(llvmKeyType, xPtr, []llvm.Value{zero, phiI}, "")
yElemPtr := b.CreateInBoundsGEP(llvmKeyType, yPtr, []llvm.Value{zero, phiI}, "")
elemEq := b.generateKeyEqual(elemType, llvmElemType, xElemPtr, yElemPtr, fn)
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
atEnd := b.CreateICmp(llvm.IntUGE, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
exitLoop := b.CreateOr(atEnd, b.CreateNot(elemEq, ""), "")
b.CreateCondBr(exitLoop, loopDone, loopBody)
bodyEnd := b.GetInsertBlock()
phiI.AddIncoming([]llvm.Value{llvm.ConstInt(b.uintptrType, 0, false), nextI},
[]llvm.BasicBlock{loopEntry, bodyEnd})
b.SetInsertPointAtEnd(loopDone)
return elemEq
default:
panic(fmt.Sprintf("unhandled key type for equal generation: %T", keyType))
} }
return nil
} }
+2 -31
View File
@@ -34,7 +34,6 @@ type functionInfo struct {
interrupt bool // go:interrupt interrupt bool // go:interrupt
nobounds bool // go:nobounds nobounds bool // go:nobounds
noescape bool // go:noescape noescape bool // go:noescape
noheap bool // go:noheap
variadic bool // go:variadic (CGo only) variadic bool // go:variadic (CGo only)
inline inlineType // go:inline inline inlineType // go:inline
} }
@@ -162,7 +161,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "machine.keepAliveNoEscape", "machine.unsafeNoEscape": case "machine.keepAliveNoEscape", "machine.unsafeNoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.alloc", "runtime.alloc_noheap", "runtime.alloc_zero": case "runtime.alloc":
// Tell the optimizer that runtime.alloc is an allocator, meaning that it // Tell the optimizer that runtime.alloc is an allocator, meaning that it
// returns values that are never null and never alias to an existing value. // returns values that are never null and never alias to an existing value.
for _, attrName := range []string{"noalias", "nonnull"} { for _, attrName := range []string{"noalias", "nonnull"} {
@@ -191,31 +190,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
case "runtime.stringFromRunes": case "runtime.stringFromRunes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0)) llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.hashmapSet":
// The key (param 2) and value (param 3) pointers are only read via
// memcpy/hash/equal and are never captured. The indirect calls
// through m.keyHash and m.keyEqual function pointers prevent LLVM's
// functionattrs pass from inferring this automatically.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGet":
// The key (param 2) is read-only and never captured.
// The value (param 3) is written to (receives the result) but never captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapDelete":
// The key (param 2) is read-only and never captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericSet":
// Same as hashmapBinarySet: key (param 2) and value (param 3) are
// not captured.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericGet":
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(3, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.hashmapGenericDelete":
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.trackPointer": case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a // This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer // portable way (see gc_stack_portable.go). Indicate to the optimizer
@@ -477,9 +451,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
if len(f.Blocks) == 0 { if len(f.Blocks) == 0 {
info.noescape = true info.noescape = true
} }
case "//go:noheap":
// Ensure this function does not allocate on the heap.
info.noheap = true
case "//go:variadic": case "//go:variadic":
// The //go:variadic pragma is emitted by the CGo preprocessing // The //go:variadic pragma is emitted by the CGo preprocessing
// pass for C variadic functions. This includes both explicit // pass for C variadic functions. This includes both explicit
@@ -569,7 +540,7 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
} }
for i := 0; i < typ.NumFields(); i++ { for i := 0; i < typ.NumFields(); i++ {
ftyp := typ.Field(i).Type() ftyp := typ.Field(i).Type()
if types.Unalias(ftyp).String() == "structs.HostLayout" { if ftyp.String() == "structs.HostLayout" {
hasHostLayout = true hasHostLayout = true
continue continue
} }
-124
View File
@@ -349,130 +349,6 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
} }
} }
// createSyscalln emits instructions for the syscall.syscalln function on
// Windows. This handles the variadic calling convention used in Go 1.26+:
//
// func syscalln(fn, n uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
//
// The function generates a switch on n to dispatch to the correct fixed-argument
// function pointer call with SetLastError(0)/GetLastError() wrapping.
func (b *builder) createSyscalln(call *ssa.CallCommon) (llvm.Value, error) {
const maxArgs = 18 // Windows syscalls support up to 18 args
isI386 := strings.HasPrefix(b.Triple, "i386-")
// Get the function pointer (call.Args[0]) and n (call.Args[1]).
fn := b.getValue(call.Args[0], getPos(call))
fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
n := b.getValue(call.Args[1], getPos(call))
// Get the variadic args slice (call.Args[2]).
// In SSA, the variadic slice is the third argument.
var argsPtr llvm.Value
if len(call.Args) > 2 {
argsSlice := b.getValue(call.Args[2], getPos(call))
argsPtr = b.CreateExtractValue(argsSlice, 0, "args.data")
} else {
argsPtr = llvm.ConstNull(b.dataPtrType)
}
// Prepare SetLastError and GetLastError.
setLastError := b.mod.NamedFunction("SetLastError")
if setLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
if isI386 {
setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
getLastError := b.mod.NamedFunction("GetLastError")
if getLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
if isI386 {
getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
retType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false)
// Create the merge block where all cases converge.
mergeBB := b.insertBasicBlock("syscalln.merge")
// Create the default (panic) block.
panicBB := b.insertBasicBlock("syscalln.panic")
// Create the switch on n.
sw := b.CreateSwitch(n, panicBB, maxArgs+1)
// We'll collect blocks and values for the PHI node.
var incomingVals []llvm.Value
var incomingBlocks []llvm.BasicBlock
// Generate a case for each arg count 0..maxArgs.
for i := 0; i <= maxArgs; i++ {
caseBB := b.insertBasicBlock("syscalln.case" + strconv.Itoa(i))
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), caseBB)
b.SetInsertPointAtEnd(caseBB)
// Load args[0] through args[i-1] from the slice data pointer.
var params []llvm.Value
var paramTypes []llvm.Type
for j := 0; j < i; j++ {
gep := b.CreateInBoundsGEP(b.uintptrType, argsPtr, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), uint64(j), false),
}, "")
arg := b.CreateLoad(b.uintptrType, gep, "")
params = append(params, arg)
paramTypes = append(paramTypes, b.uintptrType)
}
// SetLastError(0)
setCall := b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
var sp llvm.Value
if isI386 {
setCall.SetInstructionCallConv(llvm.X86StdcallCallConv)
sp = b.readStackPointer()
}
// Call fn(args...)
fnType := llvm.FunctionType(b.uintptrType, paramTypes, false)
syscallResult := b.CreateCall(fnType, fnPtr, params, "")
if isI386 {
syscallResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
b.writeStackPointer(sp)
}
// err = GetLastError()
errResult := b.CreateCall(getLastError.GlobalValueType(), getLastError, nil, "err")
if isI386 {
errResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
}
if b.uintptrType != b.ctx.Int32Type() {
errResult = b.CreateZExt(errResult, b.uintptrType, "err.uintptr")
}
// Build {r1, 0, err}
result := llvm.ConstNull(retType)
result = b.CreateInsertValue(result, syscallResult, 0, "")
result = b.CreateInsertValue(result, errResult, 2, "")
incomingVals = append(incomingVals, result)
incomingBlocks = append(incomingBlocks, b.Builder.GetInsertBlock())
b.CreateBr(mergeBB)
}
// Panic block for n > maxArgs.
b.SetInsertPointAtEnd(panicBB)
b.CreateUnreachable()
// Merge block: PHI node to select the result.
b.SetInsertPointAtEnd(mergeBB)
phi := b.CreatePHI(retType, "syscalln.result")
phi.AddIncoming(incomingVals, incomingBlocks)
return phi, nil
}
// createRawSyscallNoError emits instructions for the Linux-specific // createRawSyscallNoError emits instructions for the Linux-specific
// syscall.rawSyscallNoError function. // syscall.rawSyscallNoError function.
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) { func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
+33 -29
View File
@@ -10,30 +10,33 @@ target triple = "wasm32-unknown-wasi"
@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4 @main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4
@main.b = hidden global [2 x ptr] zeroinitializer, align 4 @main.b = hidden global [2 x ptr] zeroinitializer, align 4
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = add i32 %x, %y %0 = add i32 %x, %y
ret i32 %0 ret i32 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq i32 %x, %y %0 = icmp eq i32 %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -47,14 +50,14 @@ divbyzero.next: ; preds = %entry
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.divideByZeroPanic(ptr) #0 declare void @runtime.divideByZeroPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -64,12 +67,12 @@ divbyzero.next: ; preds = %entry
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -83,12 +86,12 @@ divbyzero.next: ; preds = %entry
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next br i1 %0, label %divbyzero.throw, label %divbyzero.next
@@ -98,66 +101,66 @@ divbyzero.next: ; preds = %entry
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(ptr undef) #2 call void @runtime.divideByZeroPanic(ptr undef) #3
unreachable unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp oeq float %x, %y %0 = fcmp oeq float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp une float %x, %y %0 = fcmp une float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp olt float %x, %y %0 = fcmp olt float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp ole float %x, %y %0 = fcmp ole float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp ogt float %x, %y %0 = fcmp ogt float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 { define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fcmp oge float %x, %y %0 = fcmp oge float %x, %y
ret i1 %0 ret i1 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 { define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
entry: entry:
ret float %x.r ret float %x.r
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 { define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 {
entry: entry:
ret float %x.i ret float %x.i
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fadd float %x.r, %y.r %0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i %1 = fadd float %x.i, %y.i
@@ -167,7 +170,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fsub float %x.r, %y.r %0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i %1 = fsub float %x.i, %y.i
@@ -177,7 +180,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = fmul float %x.r, %y.r %0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i %1 = fmul float %x.i, %y.i
@@ -191,18 +194,19 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.foo(ptr %context) unnamed_addr #1 { define hidden void @main.foo(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef) call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 { define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+25 -21
View File
@@ -6,73 +6,76 @@ target triple = "wasm32-unknown-wasi"
%runtime.channelOp = type { ptr, ptr, i32, ptr } %runtime.channelOp = type { ptr, ptr, i32, ptr }
%runtime.chanSelectState = type { ptr, ptr } %runtime.chanSelectState = type { ptr, ptr }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.chanIntSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
%chan.value = alloca i32, align 4 %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 4, ptr nonnull %chan.value)
store i32 3, ptr %chan.value, align 4 store i32 3, ptr %chan.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3 call void @runtime.chanSend(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
ret void ret void
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2 declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3
declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #0 declare void @runtime.chanSend(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2 declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
%chan.value = alloca i32, align 4 %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 4, ptr nonnull %chan.value)
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #3 %0 = call i1 @runtime.chanRecv(ptr %ch, ptr nonnull %chan.value, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %chan.value)
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void ret void
} }
declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #0 declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(36), ptr, ptr dereferenceable_or_null(16), ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3 call void @runtime.chanSend(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
%chan.op = alloca %runtime.channelOp, align 8 %chan.op = alloca %runtime.channelOp, align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %chan.op)
%0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #3 %0 = call i1 @runtime.chanRecv(ptr %ch, ptr null, ptr nonnull %chan.op, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %chan.op)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #1 { define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(36) %ch1, ptr dereferenceable_or_null(36) %ch2, ptr %context) unnamed_addr #2 {
entry: entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8 %select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4 %select.send.value = alloca i32, align 4
@@ -85,7 +88,7 @@ entry:
store ptr %ch2, ptr %0, align 4 store ptr %ch2, ptr %0, align 4
%.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12 %.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12
store ptr null, ptr %.repack3, align 4 store ptr null, ptr %.repack3, align 4
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #3 %select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca) call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
%1 = extractvalue { i32, i1 } %select.result, 0 %1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0 %2 = icmp eq i32 %1, 0
@@ -102,9 +105,10 @@ select.body: ; preds = %select.next
br label %select.done br label %select.done
} }
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #0 declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind } attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
+38 -35
View File
@@ -3,29 +3,32 @@ source_filename = "defer.go"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7m-unknown-unknown-eabi" target triple = "thumbv7m-unknown-unknown-eabi"
%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface, ptr } %runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i8, %runtime._interface }
%runtime._interface = type { ptr, ptr } %runtime._interface = type { ptr, ptr }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 { define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
declare void @main.external(ptr) #1 declare void @main.external(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferSimple(ptr %context) unnamed_addr #0 { define hidden void @main.deferSimple(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca = alloca { i32, ptr }, align 4 %defer.alloca = alloca { i32, ptr }, align 4
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4 %deferframe.buf = alloca %runtime.deferFrame, align 4
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
%defer.next = load ptr, ptr %deferPtr, align 4
store i32 0, ptr %defer.alloca, align 4 store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4 %defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
store ptr %defer.next, ptr %defer.alloca.repack15, align 4 store ptr null, ptr %defer.alloca.repack15, align 4
store ptr %defer.alloca, ptr %deferPtr, 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) #5
%setjmp.result = icmp eq i32 %setjmp, 0 %setjmp.result = icmp eq i32 %setjmp, 0
@@ -109,14 +112,14 @@ rundefers.end3: ; preds = %rundefers.loophead6
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn ; Function Attrs: nocallback nofree nosync nounwind willreturn
declare ptr @llvm.stacksave.p0() #2 declare ptr @llvm.stacksave.p0() #3
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(28), ptr, ptr) #1 declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(28), ptr) #1 declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #0 { define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
@@ -124,29 +127,29 @@ entry:
ret void ret void
} }
declare void @runtime.printlock(ptr) #1 declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #1 declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #1 declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #0 { define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca2 = alloca { i32, ptr }, align 4 %defer.alloca2 = alloca { i32, ptr }, align 4
%defer.alloca = alloca { i32, ptr }, align 4 %defer.alloca = alloca { i32, ptr }, align 4
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4 %deferframe.buf = alloca %runtime.deferFrame, align 4
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
%defer.next = load ptr, ptr %deferPtr, align 4
store i32 0, ptr %defer.alloca, align 4 store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4 %defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
store ptr %defer.next, ptr %defer.alloca.repack22, align 4 store ptr null, ptr %defer.alloca.repack22, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4 store ptr %defer.alloca, ptr %deferPtr, align 4
store i32 1, ptr %defer.alloca2, align 4 store i32 1, ptr %defer.alloca2, align 4
%defer.alloca2.repack24 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4 %defer.alloca2.repack23 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
store ptr %defer.alloca, ptr %defer.alloca2.repack24, align 4 store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
store ptr %defer.alloca2, ptr %deferPtr, 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) #5
%setjmp.result = icmp eq i32 %setjmp, 0 %setjmp.result = icmp eq i32 %setjmp, 0
@@ -250,7 +253,7 @@ rundefers.end7: ; preds = %rundefers.loophead1
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #0 { define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4 call void @runtime.printint32(i32 3, ptr undef) #4
@@ -259,7 +262,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #0 { define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printlock(ptr undef) #4 call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #4 call void @runtime.printint32(i32 5, ptr undef) #4
@@ -268,10 +271,11 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #0 { define hidden void @main.deferInfiniteLoop(ptr %context) unnamed_addr #1 {
entry: entry:
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4 %deferframe.buf = alloca %runtime.deferFrame, align 4
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.body br label %for.body
@@ -311,14 +315,12 @@ rundefers.end: ; preds = %rundefers.loophead
br label %recover br label %recover
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferLoop(ptr %context) unnamed_addr #0 { define hidden void @main.deferLoop(ptr %context) unnamed_addr #1 {
entry: entry:
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4 %deferframe.buf = alloca %runtime.deferFrame, align 4
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.loop br label %for.loop
@@ -403,11 +405,12 @@ rundefers.end1: ; preds = %rundefers.loophead4
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #0 { define hidden void @main.deferBetweenLoops(ptr %context) unnamed_addr #1 {
entry: entry:
%defer.alloca = alloca { i32, ptr, i32 }, align 4 %defer.alloca = alloca { i32, ptr, i32 }, align 4
%deferPtr = alloca ptr, align 4
store ptr null, ptr %deferPtr, align 4
%deferframe.buf = alloca %runtime.deferFrame, align 4 %deferframe.buf = alloca %runtime.deferFrame, align 4
%deferPtr = getelementptr inbounds nuw i8, ptr %deferframe.buf, i32 24
%0 = call ptr @llvm.stacksave.p0() %0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
br label %for.loop br label %for.loop
@@ -502,9 +505,9 @@ rundefers.end4: ; preds = %rundefers.loophead7
br label %recover br label %recover
} }
attributes #0 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+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,+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 = { nocallback nofree nosync nounwind willreturn } attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+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 #4 = { nounwind }
attributes #5 = { nounwind returns_twice } attributes #5 = { nounwind returns_twice }
+16 -12
View File
@@ -3,16 +3,19 @@ source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 { define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 {
entry: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -24,25 +27,25 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 { define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 {
entry: entry:
ret float 0x41F0000000000000 ret float 0x41F0000000000000
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 { define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 -1 ret i32 -1
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 { define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 {
entry: entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 } ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 { define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = uitofp i32 %v to float %0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
@@ -52,7 +55,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 { define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 {
entry: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -65,7 +68,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 { define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 {
entry: entry:
%positive = fcmp oge float %v, 0.000000e+00 %positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02 %withinmax = fcmp ole float %v, 2.550000e+02
@@ -77,7 +80,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 { define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 {
entry: entry:
%abovemin = fcmp oge float %v, -1.280000e+02 %abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02 %belowmax = fcmp ole float %v, 1.270000e+02
@@ -90,5 +93,6 @@ entry:
ret i8 %0 ret i8 %0
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
+15 -11
View File
@@ -3,44 +3,48 @@ source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 { define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp eq ptr %callback.funcptr, null %0 = icmp eq ptr %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.next: ; preds = %entry fpcall.next: ; preds = %entry
call void %callback.funcptr(i32 3, ptr %callback.context) #2 call void %callback.funcptr(i32 3, ptr %callback.context) #3
ret void ret void
fpcall.throw: ; preds = %entry fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(ptr undef) #2 call void @runtime.nilPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.nilPanic(ptr) #0 declare void @runtime.nilPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.bar(ptr %context) unnamed_addr #1 { define hidden void @main.bar(ptr %context) unnamed_addr #2 {
entry: entry:
call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef) call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 { define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+15 -18
View File
@@ -25,16 +25,19 @@ target triple = "wasm32-unknown-wasi"
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4 @"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4 @"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.newScalar(ptr %context) unnamed_addr #1 { define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -52,11 +55,8 @@ entry:
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.newArray(ptr %context) unnamed_addr #1 { define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -72,10 +72,10 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.newStruct(ptr %context) unnamed_addr #1 { define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%new = call align 1 ptr @runtime.alloc_zero(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3 call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
store ptr %new, ptr @main.struct1, align 4 store ptr %new, ptr @main.struct1, align 4
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -93,11 +93,8 @@ entry:
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc_zero(i32, ptr, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 { define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3 %new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
@@ -106,7 +103,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 { define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
@@ -128,7 +125,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 { define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3 %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
@@ -142,7 +139,7 @@ entry:
ret %runtime._interface %1 ret %runtime._interface %1
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind } attributes #3 = { nounwind }
+212 -100
View File
@@ -1,147 +1,259 @@
; ModuleID = 'generics.go' ; ModuleID = 'generics.go'
source_filename = "generics.go" source_filename = "generics.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
%"main.Point[float32]" = type { float, float }
%"main.Point[int]" = type { i32, i32 } %"main.Point[int]" = type { i32, i32 }
%"main.Point[float32]" = type { float, float }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 { define hidden void @main.main(i8* %context) unnamed_addr #1 {
entry: entry:
%0 = call %"main.Point[float32]" @"main.Add[float32]"(float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, ptr undef) %bi = alloca %"main.Point[int]", align 8
%1 = call %"main.Point[int]" @"main.Add[int]"(i32 0, i32 0, i32 0, i32 0, ptr undef) %ai = alloca %"main.Point[int]", align 8
%bf = alloca %"main.Point[float32]", align 8
%af = alloca %"main.Point[float32]", align 8
%af.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
store float 0.000000e+00, float* %af.repack, align 8
%af.repack1 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
store float 0.000000e+00, float* %af.repack1, align 4
%0 = bitcast %"main.Point[float32]"* %af to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%bf.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
store float 0.000000e+00, float* %bf.repack, align 8
%bf.repack2 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
store float 0.000000e+00, float* %bf.repack2, align 4
%1 = bitcast %"main.Point[float32]"* %bf to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
%.unpack = load float, float* %.elt, align 8
%.elt3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
%.unpack4 = load float, float* %.elt3, align 4
%.elt5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
%.unpack6 = load float, float* %.elt5, align 8
%.elt7 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
%.unpack8 = load float, float* %.elt7, align 4
%2 = call %"main.Point[float32]" @"main.Add[float32]"(float %.unpack, float %.unpack4, float %.unpack6, float %.unpack8, i8* undef)
%ai.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
store i32 0, i32* %ai.repack, align 8
%ai.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
store i32 0, i32* %ai.repack9, align 4
%3 = bitcast %"main.Point[int]"* %ai to i8*
call void @runtime.trackPointer(i8* nonnull %3, i8* undef) #2
%bi.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
store i32 0, i32* %bi.repack, align 8
%bi.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
store i32 0, i32* %bi.repack10, align 4
%4 = bitcast %"main.Point[int]"* %bi to i8*
call void @runtime.trackPointer(i8* nonnull %4, i8* undef) #2
%.elt11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
%.unpack12 = load i32, i32* %.elt11, align 8
%.elt13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
%.unpack14 = load i32, i32* %.elt13, align 4
%.elt15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
%.unpack16 = load i32, i32* %.elt15, align 8
%.elt17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
%.unpack18 = load i32, i32* %.elt17, align 4
%5 = call %"main.Point[int]" @"main.Add[int]"(i32 %.unpack12, i32 %.unpack14, i32 %.unpack16, i32 %.unpack18, i8* undef)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, ptr %context) unnamed_addr #1 { define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, i8* %context) unnamed_addr #1 {
entry: entry:
%stackalloc = alloca i8, align 1 %complit = alloca %"main.Point[float32]", align 8
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b = alloca %"main.Point[float32]", align 8
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3 %a = alloca %"main.Point[float32]", align 8
store float %a.X, ptr %a, align 4 %a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4 store float 0.000000e+00, float* %a.repack, align 8
store float %a.Y, ptr %a.repack5, align 4 %a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 store float 0.000000e+00, float* %a.repack9, align 4
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3 %0 = bitcast %"main.Point[float32]"* %a to i8*
store float %b.X, ptr %b, align 4 call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4 %a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
store float %b.Y, ptr %b.repack7, align 4 store float %a.X, float* %a.repack10, align 8
call void @main.checkSize(i32 4, ptr undef) #3 %a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
call void @main.checkSize(i32 8, ptr undef) #3 store float %a.Y, float* %a.repack11, align 4
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3 store float 0.000000e+00, float* %b.repack, align 8
%b.repack13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
store float 0.000000e+00, float* %b.repack13, align 4
%1 = bitcast %"main.Point[float32]"* %b to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%b.repack14 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
store float %b.X, float* %b.repack14, align 8
%b.repack15 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
store float %b.Y, float* %b.repack15, align 4
call void @main.checkSize(i32 4, i8* undef) #2
call void @main.checkSize(i32 8, i8* undef) #2
%complit.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
store float 0.000000e+00, float* %complit.repack, align 8
%complit.repack17 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
store float 0.000000e+00, float* %complit.repack17, align 4
%2 = bitcast %"main.Point[float32]"* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
%3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
br i1 false, label %deref.throw, label %deref.next br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry deref.next: ; preds = %entry
br i1 false, label %deref.throw, label %deref.next1 br i1 false, label %deref.throw1, label %deref.next2
deref.next1: ; preds = %deref.next deref.next2: ; preds = %deref.next
%0 = load float, ptr %a, align 4 %4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
%1 = load float, ptr %b, align 4 %5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
%2 = fadd float %0, %1 %6 = load float, float* %5, align 8
br i1 false, label %deref.throw, label %deref.next2 %7 = load float, float* %4, align 8
%8 = fadd float %6, %7
br i1 false, label %deref.throw3, label %deref.next4
deref.next2: ; preds = %deref.next1 deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw, label %deref.next3 br i1 false, label %deref.throw5, label %deref.next6
deref.next3: ; preds = %deref.next2 deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4 %9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4 %10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
%5 = load float, ptr %4, align 4 %11 = load float, float* %10, align 4
%6 = load float, ptr %3, align 4 %12 = load float, float* %9, align 4
br i1 false, label %deref.throw, label %store.next br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next3 store.next: ; preds = %deref.next6
store float %2, ptr %complit, align 4 store float %8, float* %3, align 8
br i1 false, label %deref.throw, label %store.next4 br i1 false, label %store.throw7, label %store.next8
store.next4: ; preds = %store.next store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4 %13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
%8 = fadd float %5, %6 %14 = fadd float %11, %12
store float %8, ptr %7, align 4 store float %14, float* %13, align 4
%.unpack = load float, ptr %complit, align 4 %.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
%9 = insertvalue %"main.Point[float32]" poison, float %.unpack, 0 %.unpack = load float, float* %.elt, align 8
%10 = insertvalue %"main.Point[float32]" %9, float %8, 1 %15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
ret %"main.Point[float32]" %10 %16 = insertvalue %"main.Point[float32]" %15, float %14, 1
ret %"main.Point[float32]" %16
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry deref.throw: ; preds = %entry
unreachable
deref.throw1: ; preds = %deref.next
unreachable
deref.throw3: ; preds = %deref.next2
unreachable
deref.throw5: ; preds = %deref.next4
unreachable
store.throw: ; preds = %deref.next6
unreachable
store.throw7: ; preds = %store.next
unreachable unreachable
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare void @main.checkSize(i32, i8*) #0
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
declare void @main.checkSize(i32, ptr) #0 declare void @runtime.nilPanic(i8*) #0
declare void @runtime.nilPanic(ptr) #0
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, ptr %context) unnamed_addr #1 { define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, i8* %context) unnamed_addr #1 {
entry: entry:
%stackalloc = alloca i8, align 1 %complit = alloca %"main.Point[int]", align 8
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b = alloca %"main.Point[int]", align 8
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3 %a = alloca %"main.Point[int]", align 8
store i32 %a.X, ptr %a, align 4 %a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4 store i32 0, i32* %a.repack, align 8
store i32 %a.Y, ptr %a.repack5, align 4 %a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 store i32 0, i32* %a.repack9, align 4
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3 %0 = bitcast %"main.Point[int]"* %a to i8*
store i32 %b.X, ptr %b, align 4 call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4 %a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
store i32 %b.Y, ptr %b.repack7, align 4 store i32 %a.X, i32* %a.repack10, align 8
call void @main.checkSize(i32 4, ptr undef) #3 %a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
call void @main.checkSize(i32 8, ptr undef) #3 store i32 %a.Y, i32* %a.repack11, align 4
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 %b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3 store i32 0, i32* %b.repack, align 8
%b.repack13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
store i32 0, i32* %b.repack13, align 4
%1 = bitcast %"main.Point[int]"* %b to i8*
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
%b.repack14 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
store i32 %b.X, i32* %b.repack14, align 8
%b.repack15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
store i32 %b.Y, i32* %b.repack15, align 4
call void @main.checkSize(i32 4, i8* undef) #2
call void @main.checkSize(i32 8, i8* undef) #2
%complit.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
store i32 0, i32* %complit.repack, align 8
%complit.repack17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
store i32 0, i32* %complit.repack17, align 4
%2 = bitcast %"main.Point[int]"* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
%3 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
br i1 false, label %deref.throw, label %deref.next br i1 false, label %deref.throw, label %deref.next
deref.next: ; preds = %entry deref.next: ; preds = %entry
br i1 false, label %deref.throw, label %deref.next1 br i1 false, label %deref.throw1, label %deref.next2
deref.next1: ; preds = %deref.next deref.next2: ; preds = %deref.next
%0 = load i32, ptr %a, align 4 %4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
%1 = load i32, ptr %b, align 4 %5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
%2 = add i32 %0, %1 %6 = load i32, i32* %5, align 8
br i1 false, label %deref.throw, label %deref.next2 %7 = load i32, i32* %4, align 8
%8 = add i32 %6, %7
br i1 false, label %deref.throw3, label %deref.next4
deref.next2: ; preds = %deref.next1 deref.next4: ; preds = %deref.next2
br i1 false, label %deref.throw, label %deref.next3 br i1 false, label %deref.throw5, label %deref.next6
deref.next3: ; preds = %deref.next2 deref.next6: ; preds = %deref.next4
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4 %9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4 %10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
%5 = load i32, ptr %4, align 4 %11 = load i32, i32* %10, align 4
%6 = load i32, ptr %3, align 4 %12 = load i32, i32* %9, align 4
br i1 false, label %deref.throw, label %store.next br i1 false, label %store.throw, label %store.next
store.next: ; preds = %deref.next3 store.next: ; preds = %deref.next6
store i32 %2, ptr %complit, align 4 store i32 %8, i32* %3, align 8
br i1 false, label %deref.throw, label %store.next4 br i1 false, label %store.throw7, label %store.next8
store.next4: ; preds = %store.next store.next8: ; preds = %store.next
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4 %13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
%8 = add i32 %5, %6 %14 = add i32 %11, %12
store i32 %8, ptr %7, align 4 store i32 %14, i32* %13, align 4
%.unpack = load i32, ptr %complit, align 4 %.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
%9 = insertvalue %"main.Point[int]" poison, i32 %.unpack, 0 %.unpack = load i32, i32* %.elt, align 8
%10 = insertvalue %"main.Point[int]" %9, i32 %8, 1 %15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
ret %"main.Point[int]" %10 %16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
ret %"main.Point[int]" %16
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry deref.throw: ; preds = %entry
unreachable
deref.throw1: ; preds = %deref.next
unreachable
deref.throw3: ; preds = %deref.next2
unreachable
deref.throw5: ; preds = %deref.next4
unreachable
store.throw: ; preds = %deref.next6
unreachable
store.throw7: ; preds = %store.next
unreachable unreachable
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #2 = { nounwind }
attributes #3 = { nounwind }
+17 -13
View File
@@ -5,24 +5,27 @@ target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 } %runtime._string = type { ptr, i32 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %s.data ret ptr %s.data
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp slt i16 %len, 0 %0 = icmp slt i16 %len, 0
@@ -36,24 +39,25 @@ unsafe.String.next: ; preds = %entry
%5 = zext nneg i16 %len to i32 %5 = zext nneg i16 %len to i32
%6 = insertvalue %runtime._string undef, ptr %ptr, 0 %6 = insertvalue %runtime._string undef, ptr %ptr, 0
%7 = insertvalue %runtime._string %6, i32 %5, 1 %7 = insertvalue %runtime._string %6, i32 %5, 1
call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3
ret %runtime._string %7 ret %runtime._string %7
unsafe.String.throw: ; preds = %entry unsafe.String.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(ptr undef) #2 call void @runtime.unsafeSlicePanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.unsafeSlicePanic(ptr) #0 declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.unsafeStringData(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 { define hidden ptr @main.unsafeStringData(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %s.data ret ptr %s.data
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+43 -39
View File
@@ -5,32 +5,35 @@ target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 } %runtime._string = type { ptr, i32 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #1 { define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 %a ret i32 %a
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smin.i32(i32, i32) #2 declare i32 @llvm.smin.i32(i32, i32) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #1 { define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -38,7 +41,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #1 { define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
@@ -47,109 +50,109 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #1 { define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b) %0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
ret i8 %0 ret i8 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.umin.i8(i8, i8) #2 declare i8 @llvm.umin.i8(i8, i8) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b) %0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umin.i32(i32, i32) #2 declare i32 @llvm.umin.i32(i32, i32) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #1 { define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call float @llvm.minimum.f32(float %a, float %b) %0 = call float @llvm.minimum.f32(float %a, float %b)
ret float %0 ret float %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.minimum.f32(float, float) #2 declare float @llvm.minimum.f32(float, float) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #1 { define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call double @llvm.minimum.f64(double %a, double %b) %0 = call double @llvm.minimum.f64(double %a, double %b)
ret double %0 ret double %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare double @llvm.minimum.f64(double, double) #2 declare double @llvm.minimum.f64(double, double) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.minString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.minString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1 %1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0 %2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1 %3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 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) #4 %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 %5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data %6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4 call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5 ret %runtime._string %5
} }
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b) %0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #2 declare i32 @llvm.smax.i32(i32, i32) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b) %0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
ret i32 %0 ret i32 %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #2 declare i32 @llvm.umax.i32(i32, i32) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #1 { define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call float @llvm.maximum.f32(float %a, float %b) %0 = call float @llvm.maximum.f32(float %a, float %b)
ret float %0 ret float %0
} }
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.maximum.f32(float, float) #2 declare float @llvm.maximum.f32(float, float) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.maxString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.maxString(ptr readonly %a.data, i32 %a.len, ptr readonly %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
%1 = insertvalue %runtime._string %0, i32 %a.len, 1 %1 = insertvalue %runtime._string %0, i32 %a.len, 1
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0 %2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
%3 = insertvalue %runtime._string %2, i32 %b.len, 1 %3 = insertvalue %runtime._string %2, i32 %b.len, 1
%stackalloc = alloca i8, align 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) #4 %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 %5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = select i1 %4, ptr %a.data, ptr %b.data %6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4 call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5 ret %runtime._string %5
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = shl i32 %s.len, 2 %0 = shl i32 %s.len, 2
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false) call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
@@ -157,25 +160,26 @@ entry:
} }
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #4
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.clearMap(ptr dereferenceable_or_null(48) %m, ptr %context) unnamed_addr #1 { define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
entry: entry:
call void @runtime.hashmapClear(ptr %m, ptr undef) #4 call void @runtime.hashmapClear(ptr %m, ptr undef) #5
ret void ret void
} }
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(48), ptr) #0 declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) } attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #4 = { nounwind } attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #5 = { nounwind }
+28 -28
View File
@@ -5,36 +5,39 @@ target triple = "thumbv7m-unknown-unknown-eabi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1 @"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #0 { define hidden void @main.init(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #11 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr undef) #11
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 %stacksize, ptr undef) #11
ret void ret void
} }
declare void @main.regularFunction(i32, ptr) #1 declare void @main.regularFunction(i32, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 { define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
entry: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11 call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
ret void ret void
} }
declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #1 declare i32 @"internal/task.getGoroutineStackSize"(i32, ptr) #2
declare void @"internal/task.start"(i32, ptr, i32, ptr) #1 declare void @"internal/task.start"(i32, ptr, i32, ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr undef) #11
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) #11 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) #11
@@ -42,13 +45,13 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #0 { define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 { define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef) call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
@@ -56,7 +59,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11 %n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
store i32 3, ptr %n, align 4 store i32 3, ptr %n, align 4
@@ -73,11 +76,8 @@ entry:
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #0 { define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 {
entry: entry:
store i32 7, ptr %context, align 4 store i32 7, ptr %context, align 4
ret void ret void
@@ -93,14 +93,14 @@ entry:
ret void ret void
} }
declare void @runtime.printlock(ptr) #1 declare void @runtime.printlock(ptr) #2
declare void @runtime.printint32(i32, ptr) #1 declare void @runtime.printint32(i32, ptr) #2
declare void @runtime.printunlock(ptr) #1 declare void @runtime.printunlock(ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #0 { define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry: entry:
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11 %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
@@ -126,13 +126,13 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #0 { define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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 #0 { 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: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false) call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
@@ -146,16 +146,16 @@ declare i32 @llvm.umin.i32(i32, i32) #7
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8 declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #0 { define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 {
entry: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11 call void @runtime.chanClose(ptr %ch, ptr undef) #11
ret void ret void
} }
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1 declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #2
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #0 { define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
entry: entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11 %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
store ptr %itf.value, ptr %0, align 4 store ptr %itf.value, ptr %0, align 4
@@ -186,11 +186,11 @@ entry:
ret void ret void
} }
attributes #0 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+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,+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 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.regularFunction" } attributes #2 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+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,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } attributes #3 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+armv7-m,+hwdiv,+soft-float,+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 #4 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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,+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,+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,+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 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+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 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+29 -29
View File
@@ -5,27 +5,30 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1 @"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
ret void ret void
} }
declare void @main.regularFunction(i32, ptr) #0 declare void @main.regularFunction(i32, ptr) #1
declare void @runtime.deadlock(ptr) #0 declare void @runtime.deadlock(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #2 { define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 {
entry: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @main.regularFunction(i32 %unpack.int, ptr undef) #11 call void @main.regularFunction(i32 %unpack.int, ptr undef) #11
@@ -33,23 +36,23 @@ entry:
unreachable unreachable
} }
declare void @"internal/task.start"(i32, ptr, i32, ptr) #0 declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #11
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 { define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #3 { define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #4 {
entry: entry:
%unpack.int = ptrtoint ptr %0 to i32 %unpack.int = ptrtoint ptr %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef) call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, ptr undef)
@@ -58,7 +61,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11 %n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11
@@ -79,11 +82,8 @@ entry:
ret void ret void
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #4
; Function Attrs: nounwind ; Function Attrs: nounwind
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 { define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 {
entry: entry:
store i32 7, ptr %context, align 4 store i32 7, ptr %context, align 4
ret void ret void
@@ -100,14 +100,14 @@ entry:
unreachable unreachable
} }
declare void @runtime.printlock(ptr) #0 declare void @runtime.printlock(ptr) #1
declare void @runtime.printint32(i32, ptr) #0 declare void @runtime.printint32(i32, ptr) #1
declare void @runtime.printunlock(ptr) #0 declare void @runtime.printunlock(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 { define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11 %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11
@@ -135,13 +135,13 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 { define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; 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 { 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 {
entry: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false) call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst.data, ptr align 1 %src.data, i32 %copy.n, i1 false)
@@ -155,16 +155,16 @@ declare i32 @llvm.umin.i32(i32, i32) #7
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8 declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #8
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #1 { define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(36) %ch, ptr %context) unnamed_addr #2 {
entry: entry:
call void @runtime.chanClose(ptr %ch, ptr undef) #11 call void @runtime.chanClose(ptr %ch, ptr undef) #11
ret void ret void
} }
declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #0 declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11 %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11
@@ -197,11 +197,11 @@ entry:
unreachable unreachable
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #4 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" } attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" } attributes #6 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #7 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+44 -42
View File
@@ -9,64 +9,65 @@ target triple = "wasm32-unknown-wasi"
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4 @"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4 @"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4 @"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.signature:Error:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1 @"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, { i32, [1 x ptr] }, [7 x i8] } { i8 116, i16 -32767, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, [7 x i8] c".error\00" }, align 4
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1 @"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] } }, align 4 @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.signature:String:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1 @"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
@"reflect/types.typeid:basic:int" = external constant i8 @"reflect/types.typeid:basic:int" = external constant i8
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 { define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #6 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) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null } ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 { define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #6 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) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null } ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 { define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #6 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) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null } ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 { define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %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) #6 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) #6 call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null } ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: entry:
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #6 %typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
br i1 %typecode, label %typeassert.ok, label %typeassert.next br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -76,12 +77,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next br label %typeassert.next
} }
declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #0 declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6 %0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
br i1 %0, label %typeassert.ok, label %typeassert.next br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -91,12 +92,12 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next br label %typeassert.next
} }
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #2 declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #6 %0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
br i1 %0, label %typeassert.ok, label %typeassert.next br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
@@ -106,33 +107,34 @@ typeassert.ok: ; preds = %entry
br label %typeassert.next br label %typeassert.next
} }
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #3 declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: 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) #6 %0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
ret i8 %0 ret i8 %0
} }
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #4 declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #6 %0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
%1 = extractvalue %runtime._string %0, 0 %1 = extractvalue %runtime._string %0, 0
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #6 call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
ret %runtime._string %0 ret %runtime._string %0
} }
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #5 declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" } attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" } attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" } attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
attributes #6 = { nounwind } attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
attributes #7 = { nounwind }
+16 -12
View File
@@ -3,44 +3,48 @@ source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 { define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 {
entry: entry:
ret [0 x i32] zeroinitializer ret [0 x i32] zeroinitializer
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 { define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x ret ptr %x
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 { define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x ret ptr %x
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 { define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #2 call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3
ret ptr %x ret ptr %x
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
-5
View File
@@ -115,8 +115,3 @@ func doesNotEscapeParam(a *int, b []int, c chan int, d *[0]byte)
//go:noescape //go:noescape
func stillEscapes(a *int, b []int, c chan int, d *[0]byte) { func stillEscapes(a *int, b []int, c chan int, d *[0]byte) {
} }
//go:noheap
func doesHeapAlloc() *int {
return new(int)
}
+30 -40
View File
@@ -11,105 +11,95 @@ target triple = "wasm32-unknown-wasi"
@undefinedGlobalNotInSection = external global i32, align 4 @undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024 @main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define void @extern_func() #2 { define void @extern_func() #3 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 { define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
declare void @somepkg.someFunction2(ptr) #0 declare void @somepkg.someFunction2(ptr) #1
; Function Attrs: inlinehint nounwind ; Function Attrs: inlinehint nounwind
define hidden void @main.inlineFunc(ptr %context) unnamed_addr #3 { define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 {
entry: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #4 { define hidden void @main.noinlineFunc(ptr %context) unnamed_addr #5 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.useGeneric(ptr %context) unnamed_addr #1 { define hidden void @main.useGeneric(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"main.noinlineGenericFunc[int8]"(ptr undef) call void @"main.noinlineGenericFunc[int8]"(ptr undef)
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #4 { define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #5 {
entry: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden void @main.functionInSection(ptr %context) unnamed_addr #4 section ".special_function_section" { define hidden void @main.functionInSection(ptr %context) unnamed_addr #5 section ".special_function_section" {
entry: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define void @exportedFunctionInSection() #5 section ".special_function_section" { define void @exportedFunctionInSection() #6 section ".special_function_section" {
entry: entry:
ret void ret void
} }
declare void @main.declaredImport() #6 declare void @main.declaredImport() #7
declare void @imported() #7 declare void @imported() #8
; Function Attrs: nounwind ; Function Attrs: nounwind
define void @exported() #8 { define void @exported() #9 {
entry: entry:
ret void ret void
} }
declare void @main.undefinedFunctionNotInSection(ptr) #0 declare void @main.undefinedFunctionNotInSection(ptr) #1
declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #0 declare void @main.doesNotEscapeParam(ptr nocapture dereferenceable_or_null(4), ptr nocapture, i32, i32, ptr nocapture dereferenceable_or_null(36), ptr nocapture, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.stillEscapes(ptr dereferenceable_or_null(4) %a, ptr %b.data, i32 %b.len, i32 %b.cap, ptr dereferenceable_or_null(36) %c, ptr %d, ptr %context) unnamed_addr #1 { define hidden void @main.stillEscapes(ptr dereferenceable_or_null(4) %a, ptr %b.data, i32 %b.len, i32 %b.cap, ptr dereferenceable_or_null(36) %c, ptr %d, ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
define hidden ptr @main.doesHeapAlloc(ptr %context) unnamed_addr #1 { attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
entry: attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
%stackalloc = alloca i8, align 1 attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
%new = call align 4 dereferenceable(4) ptr @runtime.alloc_noheap(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #10 attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #10 attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
ret ptr %new attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
} attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #8 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) attributes #9 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
declare noalias nonnull ptr @runtime.alloc_noheap(i32, ptr, ptr) #9
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
attributes #9 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #10 = { nounwind }
+31 -31
View File
@@ -3,28 +3,31 @@ source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi" target triple = "wasm32-unknown-wasi"
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 %ints.len ret i32 %ints.len
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 %ints.cap ret i32 %ints.cap
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 { define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 {
entry: entry:
%.not = icmp ult i32 %index, %ints.len %.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw br i1 %.not, label %lookup.next, label %lookup.throw
@@ -39,10 +42,10 @@ lookup.throw: ; preds = %entry
unreachable unreachable
} }
declare void @runtime.lookupPanic(ptr) #0 declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5 %varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
@@ -63,13 +66,10 @@ entry:
ret { ptr, i32, i32 } %4 ret { ptr, i32, i32 } %4
} }
; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #1
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #2
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #0
; Function Attrs: nounwind ; 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 #1 { 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 {
entry: entry:
%stackalloc = alloca i8, align 1 %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 nonnull inttoptr (i32 3 to ptr), ptr undef) #5 %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 nonnull inttoptr (i32 3 to ptr), ptr undef) #5
@@ -84,7 +84,7 @@ entry:
} }
; Function Attrs: nounwind ; 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 #1 { 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 {
entry: entry:
%copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len) %copy.n = call i32 @llvm.umin.i32(i32 %dst.len, i32 %src.len)
%copy.size = shl nuw i32 %copy.n, 2 %copy.size = shl nuw i32 %copy.n, 2
@@ -99,7 +99,7 @@ declare i32 @llvm.umin.i32(i32, i32) #3
declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #4 declare void @llvm.memmove.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #4
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
@@ -118,10 +118,10 @@ slice.throw: ; preds = %entry
unreachable unreachable
} }
declare void @runtime.slicePanic(ptr) #0 declare void @runtime.slicePanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
@@ -142,7 +142,7 @@ slice.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1431655765 %slice.maxcap = icmp ugt i32 %len, 1431655765
@@ -163,7 +163,7 @@ slice.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%slice.maxcap = icmp ugt i32 %len, 1073741823 %slice.maxcap = icmp ugt i32 %len, 1073741823
@@ -184,7 +184,7 @@ slice.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 { define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = getelementptr i8, ptr %p, i32 %len %0 = getelementptr i8, ptr %p, i32 %len
@@ -193,7 +193,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 { define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = trunc i64 %len to i32 %0 = trunc i64 %len to i32
@@ -203,7 +203,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = icmp ult i32 %s.len, 4 %0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
@@ -216,10 +216,10 @@ slicetoarray.throw: ; preds = %entry
unreachable unreachable
} }
declare void @runtime.sliceToArrayPointerPanic(ptr) #0 declare void @runtime.sliceToArrayPointerPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 { define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5 %makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #5
@@ -234,7 +234,7 @@ slicetoarray.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i32 %len, 1073741823 %0 = icmp ugt i32 %len, 1073741823
@@ -256,10 +256,10 @@ unsafe.Slice.throw: ; preds = %entry
unreachable unreachable
} }
declare void @runtime.unsafeSlicePanic(ptr) #0 declare void @runtime.unsafeSlicePanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp eq ptr %ptr, null %0 = icmp eq ptr %ptr, null
@@ -281,7 +281,7 @@ unsafe.Slice.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823 %0 = icmp ugt i64 %len, 1073741823
@@ -305,7 +305,7 @@ unsafe.Slice.throw: ; preds = %entry
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 { define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 {
entry: entry:
%stackalloc = alloca i8, align 1 %stackalloc = alloca i8, align 1
%0 = icmp ugt i64 %len, 1073741823 %0 = icmp ugt i64 %len, 1073741823
@@ -328,9 +328,9 @@ unsafe.Slice.throw: ; preds = %entry
unreachable unreachable
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind } attributes #5 = { nounwind }
+25 -21
View File
@@ -7,34 +7,37 @@ target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1 @"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 {
entry: entry:
ret %runtime._string { ptr @"main$string", i32 3 } ret %runtime._string { ptr @"main$string", i32 3 }
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 { define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 {
entry: entry:
ret %runtime._string zeroinitializer ret %runtime._string zeroinitializer
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i32 @main.stringLen(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #1 { define hidden i32 @main.stringLen(ptr readonly %s.data, i32 %s.len, ptr %context) unnamed_addr #2 {
entry: entry:
ret i32 %s.len ret i32 %s.len
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.stringIndex(ptr readonly %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 { define hidden i8 @main.stringIndex(ptr readonly %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 {
entry: entry:
%.not = icmp ult i32 %index, %s.len %.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw br i1 %.not, label %lookup.next, label %lookup.throw
@@ -45,40 +48,40 @@ lookup.next: ; preds = %entry
ret i8 %1 ret i8 %1
lookup.throw: ; preds = %entry lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2 call void @runtime.lookupPanic(ptr undef) #3
unreachable unreachable
} }
declare void @runtime.lookupPanic(ptr) #0 declare void @runtime.lookupPanic(ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.stringCompareEqual(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { define hidden i1 @main.stringCompareEqual(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2 %0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
ret i1 %0 ret i1 %0
} }
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.stringCompareUnequal(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { define hidden i1 @main.stringCompareUnequal(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #2 %0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3
%1 = xor i1 %0, true %1 = xor i1 %0, true
ret i1 %1 ret i1 %1
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { define hidden i1 @main.stringCompareLarger(ptr readonly %s1.data, i32 %s1.len, ptr readonly %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #2 %0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3
ret i1 %0 ret i1 %0
} }
declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #0 declare i1 @runtime.stringLess(ptr readonly, i32, ptr readonly, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i8 @main.stringLookup(ptr readonly %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 { define hidden i8 @main.stringLookup(ptr readonly %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
entry: entry:
%0 = zext i8 %x to i32 %0 = zext i8 %x to i32
%.not = icmp ugt i32 %s.len, %0 %.not = icmp ugt i32 %s.len, %0
@@ -90,10 +93,11 @@ lookup.next: ; preds = %entry
ret i8 %2 ret i8 %2
lookup.throw: ; preds = %entry lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(ptr undef) #2 call void @runtime.lookupPanic(ptr undef) #3
unreachable unreachable
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+54 -24
View File
@@ -5,16 +5,19 @@ target triple = "wasm32-unknown-wasi"
%main.hasPadding = type { i1, i32, i1 } %main.hasPadding = type { i1, i32, i1 }
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0 ; 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 ; Function Attrs: nounwind
define hidden void @main.init(ptr %context) unnamed_addr #1 { define hidden void @main.init(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 { 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: entry:
%hashmap.key = alloca %main.hasPadding, align 8 %hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -24,23 +27,29 @@ entry:
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4 store %main.hasPadding %2, ptr %hashmap.key, align 4
%3 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4 %3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds nuw 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) call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
%4 = load i32, ptr %hashmap.value, align 4 %6 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %4 ret i32 %6
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3 declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4
declare i1 @runtime.hashmapGenericGet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, i32, ptr) #0 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) ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3 declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden void @main.testZeroSet(ptr dereferenceable_or_null(48) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 { 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: entry:
%hashmap.key = alloca %main.hasPadding, align 8 %hashmap.key = alloca %main.hasPadding, align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -51,16 +60,20 @@ entry:
store i32 5, ptr %hashmap.value, align 4 store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key) call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4 store %main.hasPadding %2, ptr %hashmap.key, align 4
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4 %3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds nuw 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 12, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void ret void
} }
declare void @runtime.hashmapGenericSet(ptr dereferenceable_or_null(48), ptr nocapture, ptr nocapture, ptr) #0 declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 { define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
entry: entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -71,15 +84,23 @@ entry:
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12 %hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = call i1 @runtime.hashmapGenericGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #4 %0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds nuw 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) call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
%1 = load i32, ptr %hashmap.value, align 4 %5 = load i32, ptr %hashmap.value, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret i32 %1 ret i32 %5
} }
; Function Attrs: noinline nounwind ; Function Attrs: noinline nounwind
define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(48) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 { define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 {
entry: entry:
%hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.key = alloca [2 x %main.hasPadding], align 8
%hashmap.value = alloca i32, align 4 %hashmap.value = alloca i32, align 4
@@ -91,20 +112,29 @@ entry:
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12 %hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1 %s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4 store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
call void @runtime.hashmapGenericSet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #4 %0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds nuw 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 24, ptr nonnull %hashmap.key)
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value) call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %hashmap.value)
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.main(ptr %context) unnamed_addr #1 { define hidden void @main.main(ptr %context) unnamed_addr #2 {
entry: entry:
ret void ret void
} }
attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { nounwind } attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind }
-1
View File
@@ -38,7 +38,6 @@ func TestErrors(t *testing.T) {
{name: "loader-invaliddep"}, {name: "loader-invaliddep"},
{name: "loader-invalidpackage"}, {name: "loader-invalidpackage"},
{name: "loader-nopackage"}, {name: "loader-nopackage"},
{name: "noheap", target: "cortex-m-qemu"},
{name: "optimizer"}, {name: "optimizer"},
{name: "syntax"}, {name: "syntax"},
{name: "types"}, {name: "types"},
+9 -33
View File
@@ -1,53 +1,29 @@
module github.com/tinygo-org/tinygo module github.com/tinygo-org/tinygo
go 1.24.0 go 1.22.0
require ( require (
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/golangci/misspell v0.6.0
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-tty v0.0.4 github.com/mattn/go-tty v0.0.4
github.com/mgechev/revive v1.3.9
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
github.com/tetratelabs/wazero v1.9.0 github.com/tetratelabs/wazero v1.6.0
go.bug.st/serial v1.6.4 go.bug.st/serial v1.6.0
go.bytecodealliance.org v0.6.2 golang.org/x/net v0.35.0
go.bytecodealliance.org/cm v0.2.2 golang.org/x/sys v0.30.0
golang.org/x/net v0.50.0 golang.org/x/tools v0.30.0
golang.org/x/sys v0.41.0
golang.org/x/tools v0.42.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/espflasher v0.6.1 tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6
) )
require ( require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/creack/goselect v0.1.2 // indirect github.com/creack/goselect v0.1.2 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/stretchr/testify v1.8.4 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect golang.org/x/text v0.22.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/regclient/regclient v0.8.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/text v0.34.0 // indirect
) )
+19 -83
View File
@@ -1,38 +1,17 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg= github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw= github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw= github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M= github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -44,83 +23,40 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E= github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
tinygo.org/x/espflasher v0.6.1 h1:9jfyAP9jGjxF63FQUY2Bml9TFb5fCZYxVgbgR2IjUGs= tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74 h1:ovavgTdIBWCH8YWlcfq9gkpoyT1+IxMKSn+Df27QwE8=
tinygo.org/x/espflasher v0.6.1/go.mod h1:tr5u08HoE67WD5zxJesCiiVF/R1b6Akz3yXwh5zah8U= tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6 h1:QSnqFgNV2Ij0T4hM2qKv53fcDAFElxClPjVUZXzYkWU=
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const version = "0.42.0-dev" const version = "0.41.0-dev"
// Return TinyGo version, either in the form 0.30.0 or as a development version // Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012). // (like 0.30.0-dev-abcd012).
+30
View File
@@ -0,0 +1,30 @@
// TODO: remove this (by merging it into the top-level go.mod)
// once the top level go.mod specifies a go new enough to make our version of misspell happy.
module tools
go 1.21
require (
github.com/golangci/misspell v0.6.0
github.com/mgechev/revive v1.3.9
)
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.11.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.23.0 // indirect
)
+56
View File
@@ -0,0 +1,56 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1 -4
View File
@@ -2,15 +2,12 @@
// Install tools specified in go.mod. // Install tools specified in go.mod.
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom. // See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
package main package tools
import ( import (
_ "github.com/golangci/misspell" _ "github.com/golangci/misspell"
_ "github.com/mgechev/revive" _ "github.com/mgechev/revive"
_ "go.bytecodealliance.org/cm"
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
) )
//go:generate go install github.com/golangci/misspell/cmd/misspell //go:generate go install github.com/golangci/misspell/cmd/misspell
//go:generate go install github.com/mgechev/revive //go:generate go install github.com/mgechev/revive
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
+5
View File
@@ -0,0 +1,5 @@
# wasm-tools directory
This directory has a separate `go.mod` file because the `wasm-tools-go` module requires Go 1.22, while TinyGo itself supports Go 1.19.
When the minimum Go version for TinyGo is 1.22, this directory can be folded into `internal/tools` and the `go.mod` and `go.sum` files deleted.
+22
View File
@@ -0,0 +1,22 @@
module github.com/tinygo-org/tinygo/internal/wasm-tools
go 1.23.0
require (
go.bytecodealliance.org v0.6.2
go.bytecodealliance.org/cm v0.2.2
)
require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/regclient/regclient v0.8.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sys v0.31.0 // indirect
)
+48
View File
@@ -0,0 +1,48 @@
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+12
View File
@@ -0,0 +1,12 @@
//go:build tools
// Install tools specified in go.mod.
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
package tools
import (
_ "go.bytecodealliance.org/cm"
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
)
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
+1 -2
View File
@@ -19,7 +19,6 @@ var (
errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)") errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
errMapAlreadyCreated = errors.New("interp: map already created") errMapAlreadyCreated = errors.New("interp: map already created")
errLoopUnrolled = errors.New("interp: loop unrolled") errLoopUnrolled = errors.New("interp: loop unrolled")
errLoopTooLong = errors.New("interp: loop ran too many iterations")
) )
// This is one of the errors that can be returned from toLLVMValue when the // This is one of the errors that can be returned from toLLVMValue when the
@@ -30,7 +29,7 @@ var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not
func isRecoverableError(err error) bool { func isRecoverableError(err error) bool {
return err == errIntegerAsPointer || err == errUnsupportedInst || return err == errIntegerAsPointer || err == errUnsupportedInst ||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated || err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
err == errLoopUnrolled || err == errLoopTooLong || err == errInvalidPtrToIntSize err == errLoopUnrolled
} }
// ErrorLine is one line in a traceback. The position may be missing. // ErrorLine is one line in a traceback. The position may be missing.
+30 -33
View File
@@ -19,38 +19,35 @@ const checks = true
// runner contains all state related to one interp run. // runner contains all state related to one interp run.
type runner struct { type runner struct {
mod llvm.Module mod llvm.Module
targetData llvm.TargetData targetData llvm.TargetData
builder llvm.Builder builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData pointerSize uint32 // cached pointer size from the TargetData
dataPtrType llvm.Type // often used type so created in advance dataPtrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
byteOrder binary.ByteOrder // big-endian or little-endian byteOrder binary.ByteOrder // big-endian or little-endian
debug bool // log debug messages debug bool // log debug messages
pkgName string // package name of the currently executing package pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions functionCache map[llvm.Value]*function // cache of compiled functions
objects []object // slice of objects in memory objects []object // slice of objects in memory
globals map[llvm.Value]int // map from global to index in objects slice globals map[llvm.Value]int // map from global to index in objects slice
start time.Time start time.Time
timeout time.Duration timeout time.Duration
maxLoopIterations int callsExecuted uint64
callsExecuted uint64
interpErr error // set by Uint/Int when they encounter pointer data
} }
func newRunner(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bool) *runner { func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
r := runner{ r := runner{
mod: mod, mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()), targetData: llvm.NewTargetData(mod.DataLayout()),
byteOrder: llvmutil.ByteOrder(mod.Target()), byteOrder: llvmutil.ByteOrder(mod.Target()),
debug: debug, debug: debug,
functionCache: make(map[llvm.Value]*function), functionCache: make(map[llvm.Value]*function),
objects: []object{{}}, objects: []object{{}},
globals: make(map[llvm.Value]int), globals: make(map[llvm.Value]int),
start: time.Now(), start: time.Now(),
timeout: timeout, timeout: timeout,
maxLoopIterations: maxLoopIterations,
} }
r.pointerSize = uint32(r.targetData.PointerSize()) r.pointerSize = uint32(r.targetData.PointerSize())
r.dataPtrType = llvm.PointerType(mod.Context().Int8Type(), 0) r.dataPtrType = llvm.PointerType(mod.Context().Int8Type(), 0)
@@ -67,8 +64,8 @@ func (r *runner) dispose() {
// Run evaluates runtime.initAll function as much as possible at compile time. // Run evaluates runtime.initAll function as much as possible at compile time.
// Set debug to true if it should print output while running. // Set debug to true if it should print output while running.
func Run(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bool) error { func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
r := newRunner(mod, timeout, maxLoopIterations, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initAll := mod.NamedFunction("runtime.initAll") initAll := mod.NamedFunction("runtime.initAll")
@@ -207,10 +204,10 @@ func Run(mod llvm.Module, timeout time.Duration, maxLoopIterations int, debug bo
// RunFunc evaluates a single package initializer at compile time. // RunFunc evaluates a single package initializer at compile time.
// Set debug to true if it should print output while running. // Set debug to true if it should print output while running.
func RunFunc(fn llvm.Value, timeout time.Duration, maxLoopIterations int, debug bool) error { func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
// Create and initialize *runner object. // Create and initialize *runner object.
mod := fn.GlobalParent() mod := fn.GlobalParent()
r := newRunner(mod, timeout, maxLoopIterations, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initName := fn.Name() initName := fn.Name()
if !strings.HasSuffix(initName, ".init") { if !strings.HasSuffix(initName, ".init") {
+1 -3
View File
@@ -18,9 +18,7 @@ func TestInterp(t *testing.T) {
"copy", "copy",
"interface", "interface",
"revert", "revert",
"store",
"alloc", "alloc",
"slicedata",
} { } {
name := name // make local to this closure name := name // make local to this closure
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
@@ -46,7 +44,7 @@ func runTest(t *testing.T, pathPrefix string) {
defer mod.Dispose() defer mod.Dispose()
// Perform the transform. // Perform the transform.
err = Run(mod, 10*time.Minute, DefaultMaxInterpBlockEntries, false) err = Run(mod, 10*time.Minute, false)
if err != nil { if err != nil {
if err, match := err.(*Error); match { if err, match := err.(*Error); match {
println(err.Error()) println(err.Error())
+59 -31
View File
@@ -12,12 +12,6 @@ import (
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
// DefaultMaxInterpBlockEntries is the default maximum number of times a single
// basic block may be entered during interpretation of one function call. This
// limits how far the interpreter will unroll or evaluate loops before deferring
// the init function to runtime.
const DefaultMaxInterpBlockEntries = 1000
func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent string) (value, memoryView, *Error) { func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent string) (value, memoryView, *Error) {
mem := memoryView{r: r, parent: parentMem} mem := memoryView{r: r, parent: parentMem}
locals := make([]value, len(fn.locals)) locals := make([]value, len(fn.locals))
@@ -32,10 +26,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// This is used to prevent unrolling. // This is used to prevent unrolling.
var runtimeBlocks map[int]struct{} var runtimeBlocks map[int]struct{}
// Track how many times each basic block has been entered, to detect
// loops that are too expensive to evaluate at compile time.
var blockCounts map[int]int
// Start with the first basic block and the first instruction. // Start with the first basic block and the first instruction.
// Branch instructions may modify both bb and instIndex when branching. // Branch instructions may modify both bb and instIndex when branching.
bb := fn.blocks[0] bb := fn.blocks[0]
@@ -46,18 +36,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
for instIndex := 0; instIndex < len(bb.instructions); instIndex++ { for instIndex := 0; instIndex < len(bb.instructions); instIndex++ {
if instIndex == 0 { if instIndex == 0 {
// This is the start of a new basic block. // This is the start of a new basic block.
// Check whether this block has been entered too many times,
// which indicates an expensive loop that should be deferred
// to runtime.
if blockCounts == nil {
blockCounts = make(map[int]int)
}
blockCounts[currentBB]++
if r.maxLoopIterations > 0 && blockCounts[currentBB] > r.maxLoopIterations {
return nil, mem, r.errorAt(bb.instructions[0], errLoopTooLong)
}
if len(mem.instructions) != startRTInsts { if len(mem.instructions) != startRTInsts {
if _, ok := runtimeBlocks[lastBB]; ok { if _, ok := runtimeBlocks[lastBB]; ok {
// This loop has been unrolled. // This loop has been unrolled.
@@ -299,7 +277,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// means that monotonic time in the time package is counted from // means that monotonic time in the time package is counted from
// time.Time{}.Sub(1), which should be fine. // time.Time{}.Sub(1), which should be fine.
locals[inst.localIndex] = literalValue{uint64(0)} locals[inst.localIndex] = literalValue{uint64(0)}
case callFn.name == "runtime.alloc" || callFn.name == "runtime.alloc_noheap" || callFn.name == "runtime.alloc_zero": case callFn.name == "runtime.alloc":
// Allocate heap memory. At compile time, this is instead done // Allocate heap memory. At compile time, this is instead done
// by creating a global variable. // by creating a global variable.
@@ -435,6 +413,64 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Special function that will trigger an error. // Special function that will trigger an error.
// This is used to test error reporting. // This is used to test error reporting.
return nil, mem, r.errorAt(inst, errors.New("test error")) return nil, mem, r.errorAt(inst, errors.New("test error"))
case strings.HasSuffix(callFn.name, ".$typeassert"):
if r.debug {
fmt.Fprintln(os.Stderr, indent+"interface assert:", operands[1:])
}
// Load various values for the interface implements check below.
typecodePtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
// typecodePtr always point to the numMethod field in the type
// description struct. The methodSet, when present, comes right
// before the numMethod field (the compiler doesn't generate
// method sets for concrete types without methods).
// Considering that the compiler doesn't emit interface type
// asserts for interfaces with no methods (as the always succeed)
// then if the offset is zero, this assert must always fail.
if typecodePtr.offset() == 0 {
locals[inst.localIndex] = literalValue{uint8(0)}
break
}
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
methodSet := mem.get(methodSetPtr.index()).llvmGlobal.Initializer()
numMethods := int(r.builder.CreateExtractValue(methodSet, 0, "").ZExtValue())
llvmFn := inst.llvmInst.CalledValue()
methodSetAttr := llvmFn.GetStringAttributeAtIndex(-1, "tinygo-methods")
methodSetString := methodSetAttr.GetStringValue()
// Make a set of all the methods on the concrete type, for
// easier checking in the next step.
concreteTypeMethods := map[string]struct{}{}
for i := 0; i < numMethods; i++ {
methodInfo := r.builder.CreateExtractValue(methodSet, 1, "")
name := r.builder.CreateExtractValue(methodInfo, i, "").Name()
concreteTypeMethods[name] = struct{}{}
}
// Check whether all interface methods are also in the list
// of defined methods calculated above. This is the interface
// assert itself.
assertOk := uint8(1) // i1 true
for _, name := range strings.Split(methodSetString, "; ") {
if _, ok := concreteTypeMethods[name]; !ok {
// There is a method on the interface that is not
// implemented by the type. The assertion will fail.
assertOk = 0 // i1 false
break
}
}
// If assertOk is still 1, the assertion succeeded.
locals[inst.localIndex] = literalValue{assertOk}
case strings.HasSuffix(callFn.name, "$invoke"): case strings.HasSuffix(callFn.name, "$invoke"):
// This thunk is the interface method dispatcher: it is called // This thunk is the interface method dispatcher: it is called
// with all regular parameters and a type code. It will then // with all regular parameters and a type code. It will then
@@ -847,14 +883,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
return nil, mem, r.errorAt(inst, errUnsupportedInst) return nil, mem, r.errorAt(inst, errUnsupportedInst)
} }
// Check if an instruction triggered a recoverable error (e.g.,
// trying to interpret pointer data as integer bytes).
if r.interpErr != nil {
err := r.interpErr
r.interpErr = nil
return nil, mem, r.errorAt(inst, err)
}
} }
return nil, mem, r.errorAt(bb.instructions[len(bb.instructions)-1], errors.New("interp: reached end of basic block without terminator")) return nil, mem, r.errorAt(bb.instructions[len(bb.instructions)-1], errors.New("interp: reached end of basic block without terminator"))
} }
+18 -45
View File
@@ -299,8 +299,7 @@ func (mv *memoryView) put(index uint32, obj object) {
} }
// Load the value behind the given pointer. Returns nil if the pointer points to // Load the value behind the given pointer. Returns nil if the pointer points to
// an external global or if the load is out of bounds of the object (in which // an external global.
// case the caller defers the load to runtime).
func (mv *memoryView) load(p pointerValue, size uint32) value { func (mv *memoryView) load(p pointerValue, size uint32) value {
if checks && mv.hasExternalStore(p) { if checks && mv.hasExternalStore(p) {
panic("interp: load from object with external store") panic("interp: load from object with external store")
@@ -313,23 +312,14 @@ func (mv *memoryView) load(p pointerValue, size uint32) value {
if p.offset() == 0 && size == obj.size { if p.offset() == 0 && size == obj.size {
return obj.buffer.clone() return obj.buffer.clone()
} }
if p.offset()+size > obj.size { if checks && p.offset()+size > obj.size {
// The load is out of bounds of the object. This can happen for valid panic("interp: load out of bounds")
// Go programs, for example when dereferencing the pointer returned by
// unsafe.SliceData on a zero-capacity slice (which points to a
// zero-sized object). Return nil so the caller defers this load to
// runtime instead of crashing the compiler.
return nil
} }
v := obj.buffer.asRawValue(mv.r) v := obj.buffer.asRawValue(mv.r)
loadedBuf := v.buf[p.offset() : p.offset()+size] loadedValue := rawValue{
if _, writable := mv.objects[p.index()]; writable { buf: v.buf[p.offset() : p.offset()+size],
// This object's buffer is owned by this view, which means a later
// store may mutate it in place (see store below). Copy the loaded
// slice so the returned value is not aliased with the live buffer.
loadedBuf = append([]uint64(nil), loadedBuf...)
} }
return rawValue{buf: loadedBuf} return loadedValue
} }
// Store to the value behind the given pointer. This overwrites the value in the // Store to the value behind the given pointer. This overwrites the value in the
@@ -340,37 +330,26 @@ func (mv *memoryView) store(v value, p pointerValue) bool {
if checks && mv.hasExternalLoadOrStore(p) { if checks && mv.hasExternalLoadOrStore(p) {
panic("interp: store to object with external load/store") panic("interp: store to object with external load/store")
} }
index := p.index() obj := mv.get(p.index())
var obj object
writable := false
if mv.objects != nil {
obj, writable = mv.objects[index]
}
if !writable {
obj = mv.get(index)
}
if obj.buffer == nil { if obj.buffer == nil {
// External global, return false (for a failure). // External global, return false (for a failure).
return false return false
} }
valueLen := v.len(mv.r) if checks && p.offset()+v.len(mv.r) > obj.size {
if checks && p.offset()+valueLen > obj.size {
panic("interp: store out of bounds") panic("interp: store out of bounds")
} }
if p.offset() == 0 && valueLen == obj.buffer.len(mv.r) { if p.offset() == 0 && v.len(mv.r) == obj.buffer.len(mv.r) {
obj.buffer = v.clone() obj.buffer = v
} else { } else {
if !writable { obj = obj.clone()
obj = obj.clone()
}
buffer := obj.buffer.asRawValue(mv.r) buffer := obj.buffer.asRawValue(mv.r)
obj.buffer = buffer obj.buffer = buffer
v := v.asRawValue(mv.r) v := v.asRawValue(mv.r)
for i := uint32(0); i < valueLen; i++ { for i := uint32(0); i < v.len(mv.r); i++ {
buffer.buf[p.offset()+i] = v.buf[i] buffer.buf[p.offset()+i] = v.buf[i]
} }
} }
mv.put(index, obj) mv.put(p.index(), obj)
return true // success return true // success
} }
@@ -577,13 +556,11 @@ func (v pointerValue) asRawValue(r *runner) rawValue {
} }
func (v pointerValue) Uint(r *runner) uint64 { func (v pointerValue) Uint(r *runner) uint64 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer to integer")
return 0
} }
func (v pointerValue) Int(r *runner) int64 { func (v pointerValue) Int(r *runner) int64 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer to integer")
return 0
} }
func (v pointerValue) equal(rhs pointerValue) bool { func (v pointerValue) equal(rhs pointerValue) bool {
@@ -759,12 +736,11 @@ func (v rawValue) asRawValue(r *runner) rawValue {
return v return v
} }
func (v rawValue) bytes(r *runner) []byte { func (v rawValue) bytes() []byte {
buf := make([]byte, len(v.buf)) buf := make([]byte, len(v.buf))
for i, p := range v.buf { for i, p := range v.buf {
if p > 255 { if p > 255 {
r.interpErr = errUnsupportedInst panic("cannot convert pointer value to byte")
return buf
} }
buf[i] = byte(p) buf[i] = byte(p)
} }
@@ -772,10 +748,7 @@ func (v rawValue) bytes(r *runner) []byte {
} }
func (v rawValue) Uint(r *runner) uint64 { func (v rawValue) Uint(r *runner) uint64 {
buf := v.bytes(r) buf := v.bytes()
if r.interpErr != nil {
return 0
}
switch len(v.buf) { switch len(v.buf) {
case 1: case 1:
-23
View File
@@ -1,23 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
; Reproduction of https://github.com/tinygo-org/tinygo/issues/4214.
; Dereferencing the pointer returned by unsafe.SliceData on a zero-capacity
; slice produces a load that is out of bounds of a zero-sized object. The
; interp must defer this load to runtime instead of crashing the compiler.
@main.zeroSized = global {} zeroinitializer
@main.v = global i64 0
define void @runtime.initAll() unnamed_addr {
entry:
call void @main.init(ptr undef)
ret void
}
define internal void @main.init(ptr %context) unnamed_addr {
entry:
%val = load i64, ptr @main.zeroSized
store i64 %val, ptr @main.v
ret void
}
-12
View File
@@ -1,12 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.zeroSized = local_unnamed_addr global {} zeroinitializer
@main.v = local_unnamed_addr global i64 0
define void @runtime.initAll() unnamed_addr {
entry:
%val = load i64, ptr @main.zeroSized, align 8
store i64 %val, ptr @main.v, align 8
ret void
}
-49
View File
@@ -1,49 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@overlap.buf = global [4 x i8] c"\01\02\03\04"
@alias.src = global [4 x i8] c"\05\06\07\08"
@alias.dst = global [2 x i8] zeroinitializer
@reload.buf = global [4 x i8] c"\01\02\03\04"
@reload.out = global [2 x i8] zeroinitializer
define void @runtime.initAll() unnamed_addr {
entry:
call void @overlap.init(ptr undef)
call void @alias.init(ptr undef)
call void @reload.init(ptr undef)
ret void
}
define internal void @overlap.init(ptr %context) unnamed_addr {
entry:
%tail = getelementptr [4 x i8], ptr @overlap.buf, i32 0, i32 3
store i8 9, ptr %tail
%val = load i16, ptr @overlap.buf
%dst = getelementptr [4 x i8], ptr @overlap.buf, i32 0, i32 1
store i16 %val, ptr %dst
ret void
}
define internal void @alias.init(ptr %context) unnamed_addr {
entry:
%src = getelementptr [4 x i8], ptr @alias.src, i32 0, i32 1
%val = load i16, ptr %src
store i16 %val, ptr @alias.dst
store i8 9, ptr @alias.dst
ret void
}
define internal void @reload.init(ptr %context) unnamed_addr {
entry:
; First store makes reload.buf writable in the current memory view.
%tail = getelementptr [4 x i8], ptr @reload.buf, i32 0, i32 3
store i8 9, ptr %tail
; Partial load whose result may share the underlying buffer.
%val = load i16, ptr @reload.buf
; Subsequent in-place partial store; this must not corrupt %val.
store i8 99, ptr @reload.buf
; Write the originally-loaded value to a separate global.
store i16 %val, ptr @reload.out
ret void
}
-13
View File
@@ -1,13 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@overlap.buf = local_unnamed_addr global [4 x i8] c"\01\01\02\09"
@alias.src = local_unnamed_addr global [4 x i8] c"\05\06\07\08"
@alias.dst = local_unnamed_addr global [2 x i8] c"\09\07"
@reload.buf = local_unnamed_addr global [4 x i8] c"c\02\03\09"
@reload.out = local_unnamed_addr global [2 x i8] c"\01\02"
define void @runtime.initAll() unnamed_addr {
entry:
ret void
}
-22
View File
@@ -245,8 +245,6 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"internal/cm/": false, "internal/cm/": false,
"internal/futex/": false, "internal/futex/": false,
"internal/fuzz/": false, "internal/fuzz/": false,
"internal/itoa/": false,
"internal/poll/": false,
"internal/reflectlite/": false, "internal/reflectlite/": false,
"internal/gclayout": false, "internal/gclayout": false,
"internal/task/": false, "internal/task/": false,
@@ -269,31 +267,11 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths["crypto/internal/boring/sig/"] = false paths["crypto/internal/boring/sig/"] = false
} }
if goMinor >= 26 {
// Go 1.26 added a CPU jitter entropy source for FIPS 140-3 that
// allocates a 32 MiB global buffer (ScratchBuffer [1<<25]byte).
// This is fine on systems with virtual memory, but causes RAM
// overflow on microcontrollers. Replace with a zero-size stub
// since TinyGo targets never use FIPS jitter entropy.
paths["crypto/internal/entropy/"] = true
paths["crypto/internal/entropy/v1.0.0/"] = false
}
if needsSyscallPackage { if needsSyscallPackage {
paths["syscall/"] = true // include syscall/js paths["syscall/"] = true // include syscall/js
paths["internal/syscall/"] = true paths["internal/syscall/"] = true
paths["internal/syscall/unix/"] = false paths["internal/syscall/unix/"] = false
} }
if goMinor >= 26 {
// Go 1.26 added SWAR optimizations to unicode/utf8 that use
// constants assuming at least 32-bit uintptr. TinyGo supports
// 16-bit targets (AVR) where these constants overflow, so we
// provide a patched version.
paths["unicode/"] = true
paths["unicode/utf8/"] = false
}
return paths return paths
} }
+45 -80
View File
@@ -27,6 +27,8 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
var initFileVersions = func(info *types.Info) {}
// Program holds all packages and some metadata about the program as a whole. // Program holds all packages and some metadata about the program as a whole.
type Program struct { type Program struct {
config *compileopts.Config config *compileopts.Config
@@ -302,29 +304,6 @@ func (p *Program) Sorted() []*Package {
return p.sorted return p.sorted
} }
// StripVarInitializer removes the package-level initializer for the named
// variable from the type info. This prevents go/ssa from emitting an init
// store for it, leaving the global zero-initialized in the IR. An external
// value (e.g. from -ldflags -X via makeGlobalsModule) can then be linked in
// at final link time without any runtime init overwriting it.
//
// Must be called after Parse() (typechecking populates InitOrder) and before
// LoadSSA() (which consumes InitOrder to build the package init function).
//
// Only 1:1 var initializers (var x = expr) are matched. Multi-variable
// initializers (var x, y = f()) are left untouched.
func (p *Package) StripVarInitializer(name string) {
n := 0
for _, init := range p.info.InitOrder {
if len(init.Lhs) == 1 && init.Lhs[0].Name() == name {
continue // drop this initializer
}
p.info.InitOrder[n] = init
n++
}
p.info.InitOrder = p.info.InitOrder[:n]
}
// MainPkg returns the last package in the Sorted() slice. This is the main // MainPkg returns the last package in the Sorted() slice. This is the main
// package of the program. // package of the program.
func (p *Program) MainPkg() *Package { func (p *Program) MainPkg() *Package {
@@ -433,7 +412,7 @@ func (p *Package) Check() error {
} }
checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor) checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor)
} }
p.info.FileVersions = make(map[*ast.File]string) initFileVersions(&p.info)
// Do typechecking of the package. // Do typechecking of the package.
packageName := p.ImportPath packageName := p.ImportPath
@@ -483,7 +462,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
if !filepath.IsAbs(file) { if !filepath.IsAbs(file) {
file = filepath.Join(p.Dir, file) file = filepath.Join(p.Dir, file)
} }
f, err := p.parseFile(file, parser.ParseComments|parser.SkipObjectResolution) f, err := p.parseFile(file, parser.ParseComments)
if err != nil { if err != nil {
fileErrs = append(fileErrs, err) fileErrs = append(fileErrs, err)
return return
@@ -570,7 +549,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
} }
// Look for //go:embed comments. // Look for //go:embed comments.
var allPatterns []embedPattern var allPatterns []string
for _, comment := range doc.List { for _, comment := range doc.List {
if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") { if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") {
continue continue
@@ -598,7 +577,21 @@ func (p *Package) extractEmbedLines(addError func(error)) {
}) })
continue continue
} }
allPatterns = append(allPatterns, patterns...) for _, pattern := range patterns {
// Check that the pattern is well-formed.
// It must be valid: the Go toolchain has already
// checked for invalid patterns. But let's check
// anyway to be sure.
if _, err := path.Match(pattern, ""); err != nil {
addError(types.Error{
Fset: p.program.fset,
Pos: comment.Pos(),
Msg: "invalid pattern syntax",
})
continue
}
allPatterns = append(allPatterns, pattern)
}
} }
if len(allPatterns) != 0 { if len(allPatterns) != 0 {
@@ -631,8 +624,8 @@ func (p *Package) extractEmbedLines(addError func(error)) {
// Match all //go:embed patterns against the embed files // Match all //go:embed patterns against the embed files
// provided by `go list`. // provided by `go list`.
for _, name := range p.EmbedFiles { for _, name := range p.EmbedFiles {
for _, ep := range allPatterns { for _, pattern := range allPatterns {
if ep.Match(name) { if matchPattern(pattern, name) {
p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{ p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{
Name: name, Name: name,
NeedsData: byteSlice, NeedsData: byteSlice,
@@ -648,37 +641,13 @@ func (p *Package) extractEmbedLines(addError func(error)) {
} }
} }
// embedPattern represents a valid //go:embed pattern. // matchPattern returns true if (and only if) the given pattern would match the
// See: https://pkg.go.dev/embed#hdr-Directives // filename. The pattern could also match a parent directory of name, in which
type embedPattern struct { // case hidden files do not match.
pattern string // glob pattern without "all:" prefix func matchPattern(pattern, name string) bool {
includeHidden bool // true if "all:" prefix was present
}
// newEmbedPattern parses and validates a //go:embed pattern.
// The "all:" prefix (if present) is stripped and reflected in includeHidden.
// Returns an error if the pattern syntax is invalid.
func newEmbedPattern(s string) (embedPattern, error) {
ep := embedPattern{pattern: s}
if strings.HasPrefix(s, "all:") {
ep.pattern = s[4:]
ep.includeHidden = true
}
if _, err := path.Match(ep.pattern, ""); err != nil {
return embedPattern{}, err
}
return ep, nil
}
// Match returns true if (and only if) the pattern matches the given filename.
// The pattern could also match a parent directory of name, in which case hidden
// files do not match (unless includeHidden is true).
func (ep embedPattern) Match(name string) bool {
pattern := ep.pattern
includeHidden := ep.includeHidden
// Match this file. // Match this file.
if matched, _ := path.Match(pattern, name); matched { matched, _ := path.Match(pattern, name)
if matched {
return true return true
} }
@@ -692,20 +661,17 @@ func (ep embedPattern) Match(name string) bool {
dir = path.Clean(dir) dir = path.Clean(dir)
if matched, _ := path.Match(pattern, dir); matched { if matched, _ := path.Match(pattern, dir); matched {
// Pattern matches the directory. // Pattern matches the directory.
if !includeHidden { suffix := name[len(dir):]
suffix := name[len(dir):] if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") { // Pattern matches a hidden file.
// Pattern matches a hidden file. // Hidden files are included when listed directly as a
// Hidden files are included when listed directly as a // pattern, but not when they are part of a directory tree.
// pattern, or when the "all:" prefix is used, but not // Source:
// when they are part of a directory tree without "all:". // > If a pattern names a directory, all files in the
// Source: // > subtree rooted at that directory are embedded
// > If a pattern names a directory, all files in the // > (recursively), except that files with names beginning
// > subtree rooted at that directory are embedded // > with . or _ are excluded.
// > (recursively), except that files with names beginning return false
// > with . or _ are excluded.
return false
}
} }
return true return true
} }
@@ -714,12 +680,11 @@ func (ep embedPattern) Match(name string) bool {
// parseGoEmbed is like strings.Fields but for a //go:embed line. It parses // parseGoEmbed is like strings.Fields but for a //go:embed line. It parses
// regular fields and quoted fields (that may contain spaces). // regular fields and quoted fields (that may contain spaces).
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPattern, err error) { func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, err error) {
args = strings.TrimSpace(args) args = strings.TrimSpace(args)
initialLen := len(args) initialLen := len(args)
for args != "" { for args != "" {
patternPos := pos + token.Pos(initialLen-len(args)) patternPos := pos + token.Pos(initialLen-len(args))
var pattern string
switch args[0] { switch args[0] {
case '`', '"', '\\': case '`', '"', '\\':
// Parse the next pattern using the Go scanner. // Parse the next pattern using the Go scanner.
@@ -738,7 +703,8 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPatt
Msg: "invalid quoted string in //go:embed", Msg: "invalid quoted string in //go:embed",
} }
} }
pattern = constant.StringVal(constant.MakeFromLiteral(lit, tok, 0)) pattern := constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
patterns = append(patterns, pattern)
args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace) args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace)
default: default:
// The value is just a regular value. // The value is just a regular value.
@@ -747,18 +713,17 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPatt
if index < 0 { if index < 0 {
index = len(args) index = len(args)
} }
pattern = args[:index] pattern := args[:index]
patterns = append(patterns, pattern)
args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace) args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace)
} }
ep, err := newEmbedPattern(pattern) if _, err := path.Match(patterns[len(patterns)-1], ""); err != nil {
if err != nil {
return nil, types.Error{ return nil, types.Error{
Fset: p.program.fset, Fset: p.program.fset,
Pos: patternPos, Pos: patternPos,
Msg: "invalid pattern syntax", Msg: "invalid pattern syntax",
} }
} }
patterns = append(patterns, ep)
} }
return patterns, nil return patterns, nil
} }
+17
View File
@@ -0,0 +1,17 @@
//go:build go1.22
// types.Info.FileVersions was added in Go 1.22, so we can only initialize it
// when built with Go 1.22.
package loader
import (
"go/ast"
"go/types"
)
func init() {
initFileVersions = func(info *types.Info) {
info.FileVersions = make(map[*ast.File]string)
}
}
+40 -209
View File
@@ -30,18 +30,14 @@ import (
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics" "github.com/tinygo-org/tinygo/diagnostics"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/interp"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/buildutil" "golang.org/x/tools/go/buildutil"
"tinygo.org/x/espflasher/pkg/espflasher"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
"go.bug.st/serial" "go.bug.st/serial"
"go.bug.st/serial/enumerator" "go.bug.st/serial/enumerator"
) )
var errInheritableOnly = errors.New("target is inheritable-only, which means it cannot be used directly for building or flashing")
// commandError is an error type to wrap os/exec.Command errors. This provides // commandError is an error type to wrap os/exec.Command errors. This provides
// some more information regarding what went wrong while running a command. // some more information regarding what went wrong while running a command.
type commandError struct { type commandError struct {
@@ -143,10 +139,6 @@ func printCommand(cmd string, args ...string) {
// Build compiles and links the given package and writes it to outpath. // Build compiles and links the given package and writes it to outpath.
func Build(pkgName, outpath string, config *compileopts.Config) error { func Build(pkgName, outpath string, config *compileopts.Config) error {
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
// Create a temporary directory for intermediary files. // Create a temporary directory for intermediary files.
tmpdir, err := os.MkdirTemp("", "tinygo") tmpdir, err := os.MkdirTemp("", "tinygo")
if err != nil { if err != nil {
@@ -209,8 +201,6 @@ func Build(pkgName, outpath string, config *compileopts.Config) error {
// Test runs the tests in the given package. Returns whether the test passed and // Test runs the tests in the given package. Returns whether the test passed and
// possibly an error if the test failed to run. // possibly an error if the test failed to run.
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, outpath string) (bool, error) { func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, outpath string) (bool, error) {
optionsCopy := *options
options = &optionsCopy
options.TestConfig.CompileTestBinary = true options.TestConfig.CompileTestBinary = true
config, err := builder.NewConfig(options) config, err := builder.NewConfig(options)
if err != nil { if err != nil {
@@ -366,10 +356,6 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
return err return err
} }
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
// determine the type of file to compile // determine the type of file to compile
var fileExt string var fileExt string
@@ -397,12 +383,8 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
fileExt = filepath.Ext(config.Target.FlashFilename) fileExt = filepath.Ext(config.Target.FlashFilename)
case "openocd": case "openocd":
fileExt = ".hex" fileExt = ".hex"
case "bmp", "probe-rs": case "bmp":
fileExt = ".elf" fileExt = ".elf"
case "adb":
fileExt = ".hex"
case "esp32flash", "esp32jtag":
fileExt = ".bin"
case "native": case "native":
return errors.New("unknown flash method \"native\" - did you miss a -target flag?") return errors.New("unknown flash method \"native\" - did you miss a -target flag?")
default: default:
@@ -537,71 +519,11 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
case "probe-rs":
// TODO: this halts the target after flashing.
// See: https://github.com/probe-rs/probe-rs/discussions/4005
cmd := executeCommand(config.Options, "probe-rs", "download", "--chip="+config.Target.ProbeRSChip, "--verify", result.Binary)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return &commandError{"failed to flash", result.Binary, err}
}
case "adb":
// Run pre-flash adb shell commands.
for _, preCmd := range config.Target.ADBPreCommands {
cmd := executeCommand(config.Options, "adb", "shell", preCmd)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"failed to run adb pre-command", preCmd, err}
}
}
// Push the binary to the device.
if config.Target.ADBPushRemote == "" {
return errors.New("invalid target file: flash-method was set to \"adb\" but no adb-push-remote was set")
}
cmd := executeCommand(config.Options, "adb", "push", result.Binary, config.Target.ADBPushRemote)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"adb push failed to " + config.Target.ADBPushRemote, result.Binary, err}
}
// Run post-flash adb shell commands.
for _, postCmd := range config.Target.ADBPostCommands {
postCmd = strings.ReplaceAll(postCmd, "{remote}", config.Target.ADBPushRemote)
cmd := executeCommand(config.Options, "adb", "shell", postCmd)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return &commandError{"failed to run adb post-command", postCmd, err}
}
}
case "esp32flash":
port, err := getDefaultPort(port, config.Target.SerialPort)
if err != nil {
return &commandError{"failed to find port", port, err}
}
if err := flashBinUsingEsp32(port, classicReset, result.Binary, config.Options); err != nil {
return &commandError{"failed to flash", result.Binary, err}
}
case "esp32jtag":
port, err := getDefaultPort(port, config.Target.SerialPort)
if err != nil {
return &commandError{"failed to find port", port, err}
}
if err := flashBinUsingEsp32(port, jtagReset, result.Binary, config.Options); err != nil {
return &commandError{"failed to flash", result.Binary, err}
}
default: default:
return fmt.Errorf("unknown flash method: %s", flashMethod) return fmt.Errorf("unknown flash method: %s", flashMethod)
} }
if options.Monitor { if options.Monitor {
return Monitor(result.Executable, port, config) return Monitor(result.Executable, "", config)
} }
return nil return nil
} }
@@ -709,21 +631,6 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
daemon.Stdout = w daemon.Stdout = w
daemon.Stderr = w daemon.Stderr = w
} }
case "probe-rs":
port = ":1337"
gdbCommands = append(gdbCommands, "monitor halt", "load", "monitor reset halt")
daemon = executeCommand(config.Options, "probe-rs", "gdb", "--chip="+config.Target.ProbeRSChip)
if ocdOutput {
// Make it clear which output is from the daemon.
w := &ColorWriter{
Out: colorable.NewColorableStderr(),
Prefix: "probe-rs: ",
Color: TermColorYellow,
}
daemon.Stdout = w
daemon.Stderr = w
}
case "jlink": case "jlink":
port = ":2331" port = ":2331"
gdbCommands = append(gdbCommands, "load", "monitor reset halt") gdbCommands = append(gdbCommands, "load", "monitor reset halt")
@@ -858,10 +765,6 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
return err return err
} }
if config.Target != nil && config.Target.InheritableOnly {
return errInheritableOnly
}
_, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error { _, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run() return cmd.Run()
}) })
@@ -1116,68 +1019,6 @@ func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Opt
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]") return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
} }
const (
defaultReset = "default"
classicReset = "classic"
jtagReset = "jtag"
)
func flashBinUsingEsp32(port, resetMode, tmppath string, options *compileopts.Options) error {
opts := espflasher.DefaultOptions()
opts.Compress = true
opts.Logger = &espflasher.StdoutLogger{W: os.Stdout}
if options.BaudRate != 0 {
opts.FlashBaudRate = options.BaudRate
}
if resetMode == jtagReset {
opts.ResetMode = espflasher.ResetUSBJTAG
}
flasher, err := espflasher.New(port, opts)
if err != nil {
return err
}
defer flasher.Close()
chipName := flasher.ChipName()
offset := uint32(0x0)
if chipName == "ESP32" {
offset = 0x1000
}
// Read the firmware binary
data, err := os.ReadFile(tmppath)
if err != nil {
return err
}
if err := flasher.EraseFlash(); err != nil {
return fmt.Errorf("erase failed: %v", err)
}
progress := func(current, total int) {
pct := float64(current) / float64(total) * 100
bar := int(pct / 2)
fmt.Printf("\r[%-50s] %6.1f%%", strings.Repeat("#", bar)+strings.Repeat(".", 50-bar), pct)
if current >= total {
fmt.Println()
}
}
// Flash with progress reporting
err = flasher.FlashImage(data, offset, progress)
if err != nil {
return err
}
fmt.Println()
// Reset the device to run the new firmware
flasher.Reset()
return nil
}
type mountPoint struct { type mountPoint struct {
name string name string
path string path string
@@ -1766,7 +1607,6 @@ func main() {
serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)") serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)")
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit") work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout") interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
interpLoopLimit := flag.Int("interp-loop-limit", interp.DefaultMaxInterpBlockEntries, "maximum loop iterations during interp (0 to disable)")
var tags buildutil.TagsFlag var tags buildutil.TagsFlag
flag.Var(&tags, "tags", "a space-separated list of extra build tags") flag.Var(&tags, "tags", "a space-separated list of extra build tags")
target := flag.String("target", "", "chip/board name or JSON target specification file") target := flag.String("target", "", "chip/board name or JSON target specification file")
@@ -1780,7 +1620,6 @@ func main() {
printSize := flag.String("size", "", "print sizes (none, short, full, html)") printSize := flag.String("size", "", "print sizes (none, short, full, html)")
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printAllocsCoverString := flag.String("print-allocs-cover", "", "like -print-allocs, but in go coverage tool format")
printCommands := flag.Bool("x", false, "Print commands") printCommands := flag.Bool("x", false, "Print commands")
flagJSON := flag.Bool("json", false, "print output in JSON format") flagJSON := flag.Bool("json", false, "print output in JSON format")
parallelism := flag.Int("p", runtime.GOMAXPROCS(0), "the number of build jobs that can run in parallel") parallelism := flag.Int("p", runtime.GOMAXPROCS(0), "the number of build jobs that can run in parallel")
@@ -1861,14 +1700,8 @@ func main() {
} }
var printAllocs *regexp.Regexp var printAllocs *regexp.Regexp
printAllocsCover := false if *printAllocsString != "" {
printAllocsPattern := *printAllocsString printAllocs, err = regexp.Compile(*printAllocsString)
if *printAllocsCoverString != "" {
printAllocsPattern = *printAllocsCoverString
printAllocsCover = true
}
if printAllocsPattern != "" {
printAllocs, err = regexp.Compile(printAllocsPattern)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
@@ -1891,44 +1724,42 @@ func main() {
} }
options := &compileopts.Options{ options := &compileopts.Options{
GOOS: goenv.Get("GOOS"), GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
GOMIPS: goenv.Get("GOMIPS"), GOMIPS: goenv.Get("GOMIPS"),
Target: *target, Target: *target,
BuildMode: *buildMode, BuildMode: *buildMode,
StackSize: stackSize, StackSize: stackSize,
Opt: *opt, Opt: *opt,
GC: *gc, GC: *gc,
PanicStrategy: *panicStrategy, PanicStrategy: *panicStrategy,
Scheduler: *scheduler, Scheduler: *scheduler,
Serial: *serial, Serial: *serial,
Work: *work, Work: *work,
InterpTimeout: *interpTimeout, InterpTimeout: *interpTimeout,
InterpMaxLoopIterations: *interpLoopLimit, PrintIR: *printIR,
PrintIR: *printIR, DumpSSA: *dumpSSA,
DumpSSA: *dumpSSA, VerifyIR: *verifyIR,
VerifyIR: *verifyIR, SkipDWARF: *skipDwarf,
SkipDWARF: *skipDwarf, Semaphore: make(chan struct{}, *parallelism),
Semaphore: make(chan struct{}, *parallelism), Debug: !*nodebug,
Debug: !*nodebug, Nobounds: *nobounds,
Nobounds: *nobounds, PrintSizes: *printSize,
PrintSizes: *printSize, PrintStacks: *printStacks,
PrintStacks: *printStacks, PrintAllocs: printAllocs,
PrintAllocs: printAllocs, Tags: []string(tags),
PrintAllocsCover: printAllocsCover, TestConfig: testConfig,
Tags: []string(tags), GlobalValues: globalVarValues,
TestConfig: testConfig, Programmer: *programmer,
GlobalValues: globalVarValues, OpenOCDCommands: ocdCommands,
Programmer: *programmer, LLVMFeatures: *llvmFeatures,
OpenOCDCommands: ocdCommands, Monitor: *monitor,
LLVMFeatures: *llvmFeatures, BaudRate: *baudrate,
Monitor: *monitor, Timeout: *timeout,
BaudRate: *baudrate, WITPackage: witPackage,
Timeout: *timeout, WITWorld: witWorld,
WITPackage: witPackage, GoCompatibility: *gocompatibility,
WITWorld: witWorld,
GoCompatibility: *gocompatibility,
} }
if *printCommands { if *printCommands {
options.PrintCommands = printCommand options.PrintCommands = printCommand
+10 -25
View File
@@ -46,6 +46,15 @@ var supportedLinuxArches = map[string]string{
"WASIp1": "wasip1/wasm", "WASIp1": "wasip1/wasm",
} }
func init() {
major, _, _ := goenv.GetGorootVersion()
if major < 21 {
// Go 1.20 backwards compatibility.
// Should be removed once we drop support for Go 1.20.
delete(supportedLinuxArches, "WASIp1")
}
}
var sema = make(chan struct{}, runtime.NumCPU()) var sema = make(chan struct{}, runtime.NumCPU())
func TestBuild(t *testing.T) { func TestBuild(t *testing.T) {
@@ -67,10 +76,7 @@ func TestBuild(t *testing.T) {
"init_multi.go", "init_multi.go",
"interface.go", "interface.go",
"json.go", "json.go",
"localtypes/",
"localtypes.go",
"map.go", "map.go",
"map_bigkey.go",
"math.go", "math.go",
"oldgo/", "oldgo/",
"print.go", "print.go",
@@ -101,9 +107,6 @@ func TestBuild(t *testing.T) {
if minor >= 23 { if minor >= 23 {
tests = append(tests, "go1.23/") tests = append(tests, "go1.23/")
} }
if minor >= 24 {
tests = append(tests, "typealias.go")
}
if *testTarget != "" { if *testTarget != "" {
// This makes it possible to run one specific test (instead of all), // This makes it possible to run one specific test (instead of all),
@@ -149,19 +152,6 @@ func TestBuild(t *testing.T) {
} }
runTestWithConfig("ldflags.go", t, opts, nil, nil) runTestWithConfig("ldflags.go", t, opts, nil, nil)
}) })
// Same as ldflags, but the global has a default value in source.
// -ldflags -X must override it, matching standard Go behaviour.
t.Run("ldflags-initialized", func(t *testing.T) {
t.Parallel()
opts := optionsFromTarget("", sema)
opts.GlobalValues = map[string]map[string]string{
"main": {
"someGlobal": "foobar",
},
}
runTestWithConfig("ldflags-initialized.go", t, opts, nil, nil)
})
}) })
if testing.Short() { if testing.Short() {
@@ -290,11 +280,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// limited amount of memory. // limited amount of memory.
continue continue
case "map_bigkey.go":
// Compiler generates many large stack temporaries for [256]byte
// map keys, overflowing the goroutine stack (384 bytes).
continue
case "gc.go": case "gc.go":
// Does not pass due to high mark false positive rate. // Does not pass due to high mark false positive rate.
continue continue
@@ -466,7 +451,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
// Build the test binary. // Build the test binary.
stdout := &bytes.Buffer{} stdout := &bytes.Buffer{}
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, 2*time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error { _, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
return cmd.Run() return cmd.Run()
}) })
if err != nil { if err != nil {
+1 -1
View File
@@ -278,7 +278,7 @@ func ListSerialPorts() ([]SerialPortInfo, error) {
return serialPortInfo, nil return serialPortInfo, nil
} }
var addressMatch = regexp.MustCompile(`panic: runtime error at 0x([0-9a-f]+): `) var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `)
// Extract the address from the "panic: runtime error at" message. // Extract the address from the "panic: runtime error at" message.
func extractPanicAddress(line []byte) uint64 { func extractPanicAddress(line []byte) uint64 {
@@ -1,56 +0,0 @@
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Stripped-down version of the entropy package for TinyGo.
//
// The upstream Go 1.26 package allocates a [1<<25]byte (32 MiB) global buffer
// for CPU jitter-based SP 800-90B entropy collection. This is fine on systems
// with virtual memory where BSS pages are lazily backed, but it causes a fatal
// "RAM overflowed" error on microcontrollers and other memory-constrained
// targets.
//
// Because FIPS 140-3 jitter entropy is never used on TinyGo targets (the DRBG
// falls through to sysrand.Read when fips140.Enabled is false), this overlay
// replaces the 32 MiB buffer with a zero-size type.
package entropy
// Version returns the version of the entropy source.
func Version() string {
return "v1.0.0"
}
// ScratchBuffer is a large buffer in upstream Go (32 MiB). TinyGo replaces it
// with a zero-size type since the CPU jitter entropy source is not used.
type ScratchBuffer [0]byte
// Seed returns a 384-bit seed with full entropy.
// On TinyGo targets this is never called because FIPS mode is not enabled.
func Seed(memory *ScratchBuffer) ([48]byte, error) {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// Samples collects entropy samples. Not supported on TinyGo targets.
func Samples(samples []uint8, memory *ScratchBuffer) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// SHA384 computes SHA-384 over 1024 bytes. Not supported on TinyGo targets.
func SHA384(p *[1024]byte) [48]byte {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// TestingOnlySHA384 computes SHA-384 over arbitrary bytes. Not supported on TinyGo targets.
func TestingOnlySHA384(p []byte) [48]byte {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// RepetitionCountTest implements the repetition count test from SP 800-90B.
func RepetitionCountTest(samples []uint8) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
// AdaptiveProportionTest implements the adaptive proportion test from SP 800-90B.
func AdaptiveProportionTest(samples []uint8) error {
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
}
+1 -1
View File
@@ -20,7 +20,7 @@ type reader struct {
func (r *reader) Read(b []byte) (n int, err error) { func (r *reader) Read(b []byte) (n int, err error) {
if len(b) != 0 { if len(b) != 0 {
libc_arc4random_buf(unsafe.Pointer(unsafe.SliceData(b)), uint(len(b))) libc_arc4random_buf(unsafe.Pointer(&b[0]), uint(len(b)))
} }
return len(b), nil return len(b), nil
} }
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) //go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt)
// If you update the above build constraint, you'll probably also need to update // If you update the above build constraint, you'll probably also need to update
// src/runtime/rand_hwrng.go. // src/runtime/rand_hwrng.go.
+1 -1
View File
@@ -25,7 +25,7 @@ func (r *reader) Read(b []byte) (n int, err error) {
// See for example: https://github.com/golang/go/issues/33542 // See for example: https://github.com/golang/go/issues/33542
// For Windows 7 and newer, we might switch to ProcessPrng in the future // For Windows 7 and newer, we might switch to ProcessPrng in the future
// (which is a documented function and might be a tiny bit faster). // (which is a documented function and might be a tiny bit faster).
ok := libc_RtlGenRandom(unsafe.Pointer(unsafe.SliceData(b)), len(b)) ok := libc_RtlGenRandom(unsafe.Pointer(&b[0]), len(b))
if !ok { if !ok {
return 0, errRandom return 0, errRandom
} }
-66
View File
@@ -1,66 +0,0 @@
// This is a very minimal bootloader for the ESP32-C6. It only initializes the
// flash and then continues with the generic RISC-V initialization code, which
// in turn will call runtime.main.
// It is written in assembly (and not in a higher level language) to make sure
// it is entirely loaded into IRAM and doesn't accidentally call functions
// stored in IROM.
//
// The ESP32-C6 has a unified IRAM/DRAM address space at 0x40800000, and
// separate DROM (0x42800000) / IROM (0x42000000) flash-mapped regions.
.section .init
.global call_start_cpu0
.type call_start_cpu0,@function
call_start_cpu0:
// At this point:
// - The ROM bootloader is finished and has jumped to here.
// - We're running from IRAM: both IRAM and DRAM segments have been loaded
// by the ROM bootloader.
// - We have a usable stack (but not the one we would like to use).
// - No flash mappings (MMU) are set up yet.
// Reset MMU, see bootloader_reset_mmu in the ESP-IDF.
call Cache_Suspend_ICache
mv s0, a0 // autoload value
call Cache_Invalidate_ICache_All
call Cache_MMU_Init
// Set up flash mapping (both IROM and DROM).
// On ESP32-C6, Cache_Dbus_MMU_Set is replaced by Cache_MSPI_MMU_Set
// which has an extra "sensitive" parameter.
// C equivalent:
// Cache_MSPI_MMU_Set(0, 0, 0x42000000, 0, 64, 256, 0)
// Maps 16MB starting at 0x42000000, covering both IROM and DROM.
li a0, 0 // sensitive: no flash encryption
li a1, 0 // ext_ram: MMU_ACCESS_FLASH
li a2, 0x42000000 // vaddr: start of flash-mapped region
li a3, 0 // paddr: physical address in the flash chip
li a4, 64 // psize: always 64 (kilobytes)
li a5, 256 // num: pages (16MB / 64K = 256, covers IROM+DROM)
li a6, 0 // fixed
call Cache_MSPI_MMU_Set
// Enable the flash cache.
mv a0, s0 // restore autoload value from Cache_Suspend_ICache call
call Cache_Resume_ICache
// Jump to generic RISC-V initialization, which initializes the stack
// pointer and globals register. It should not return.
j _start
.section .text.exception_vectors
.global _vector_table
.type _vector_table,@function
_vector_table:
.option push
.option norvc
.rept 32
j handleInterruptASM /* interrupt handler */
.endr
.option pop
.size _vector_table, .-_vector_table
-397
View File
@@ -1,397 +0,0 @@
// Startup code for the ESP32-S3 (Xtensa LX7, windowed ABI).
//
// The ROM bootloader loads IRAM/DRAM segments into SRAM but does NOT
// configure flash cache/MMU. We must:
// 1. Set up the windowed-ABI register file and stack pointer.
// 2. Set VECBASE and clear PS.EXCM (needed for callx4 window overflows).
// 3. Disable watchdog timers.
// 4. Configure the flash cache and MMU so IROM/DROM are accessible.
// 5. Jump to runtime.main (in IROM).
//
// Cache/MMU init sequence (from NuttX esp_loader.c / ESP-IDF bootloader / esp-hal):
// Phase A configure cache modes:
// a. rom_config_instruction_cache_mode(16KB, 8-way, 32B)
// b. rom_Cache_Suspend_DCache()
// c. rom_config_data_cache_mode(32KB, 8-way, 32B)
// d. Cache_Resume_DCache(0)
// Phase B map flash pages:
// e. Disable caches
// f. Cache_MMU_Init() reset all MMU entries to invalid
// g. Cache_Set_IDROM_MMU_Size() set IROM/DROM entry split
// h. Write MMU entries mapping flash page 0 for IROM and DROM
// i. Clear bus-shut bits
// j. Enable caches + isync
#define PS_WOE 0x00040000
// -----------------------------------------------------------------------
// Boot entry point placed in IRAM by the linker.
// -----------------------------------------------------------------------
.section .text.call_start_cpu0
.literal_position
.align 4
.Lstack_top_addr:
.long _stack_top
.Lmain_addr:
.long main
.Lvector_table_addr:
.long _vector_table
// WDT register addresses
.Lwdt_key:
.long 0x50D83AA1
.Lrtc_wdt_protect:
.long 0x600080B0
.Lrtc_wdt_config0:
.long 0x60008098
.Ltimg0_wdt_protect:
.long 0x6001F064
.Ltimg0_wdt_config0:
.long 0x6001F048
.Ltimg1_wdt_protect:
.long 0x60020064
.Ltimg1_wdt_config0:
.long 0x60020048
.Lswd_protect:
.long 0x600080B8
.Lswd_key:
.long 0x8F1D312A
.Lswd_conf:
.long 0x600080B4
.Lswd_disable:
.long 0x40000000
// ROM function addresses (from ESP-IDF esp32s3.rom.ld)
.Lrom_config_icache:
.long 0x40001a1c
.Lrom_config_dcache:
.long 0x40001a28
.Lrom_suspend_dcache:
.long 0x400018b4
.LCache_Resume_DCache:
.long 0x400018c0
.LCache_Disable_ICache:
.long 0x4000186c
.LCache_Disable_DCache:
.long 0x40001884
.LCache_MMU_Init:
.long 0x40001998
.LCache_Set_IDROM_MMU_Size:
.long 0x40001914
.LCache_Enable_ICache:
.long 0x40001878
.LCache_Enable_DCache:
.long 0x40001890
// Cache/MMU register addresses
.Lmmu_table_base:
.long 0x600C5000
.Licache_ctrl1_reg:
.long 0x600C4064
.Ldcache_ctrl1_reg:
.long 0x600C4004
// End-of-section symbols for multi-page MMU mapping.
.Lirom_end:
.long _irom_end
.Ldrom_end:
.long _drom_end
.Lirom_base:
.long 0x42000000
.Ldrom_base:
.long 0x3C000000
.global call_start_cpu0
call_start_cpu0:
// ---- 1. Windowed-ABI register file setup ----
// Disable WOE so we can safely manipulate WINDOWSTART.
rsr.ps a2
movi a3, ~(PS_WOE)
and a2, a2, a3
wsr.ps a2
rsync
// Set WINDOWSTART to 1 << WINDOWBASE (mark only current window as valid).
rsr.windowbase a2
ssl a2
movi a2, 1
sll a2, a2
wsr.windowstart a2
rsync
// Load stack pointer.
l32r a1, .Lstack_top_addr
// Re-enable WOE.
rsr.ps a2
movi a3, PS_WOE
or a2, a2, a3
wsr.ps a2
rsync
// Enable FPU (coprocessor 0).
movi a2, 1
wsr.cpenable a2
rsync
// ---- 2. Disable all watchdog timers (IMMEDIATELY, before any delay) ----
l32r a3, .Lwdt_key
movi a4, 0
// RTC WDT
l32r a2, .Lrtc_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Lrtc_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// TIMG0 WDT
l32r a2, .Ltimg0_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Ltimg0_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// TIMG1 WDT
l32r a2, .Ltimg1_wdt_protect
memw
s32i a3, a2, 0
l32r a5, .Ltimg1_wdt_config0
memw
s32i a4, a5, 0
memw
s32i a4, a2, 0
// Super WDT
l32r a2, .Lswd_protect
l32r a3, .Lswd_key
memw
s32i a3, a2, 0
l32r a5, .Lswd_conf
l32r a6, .Lswd_disable
memw
s32i a6, a5, 0
memw
s32i a4, a2, 0
// ---- 3. Set VECBASE and clear PS.EXCM ----
// VECBASE must be set before any callx4 so that window overflow
// exceptions (triggered by register window rotation) route to our
// handlers in IRAM, not the ROM's default vectors.
l32r a8, .Lvector_table_addr
wsr.vecbase a8
rsync
// Clear PS.EXCM (bit 4) and PS.INTLEVEL (bits 0-3).
// The ROM bootloader may leave EXCM=1; with EXCM set any callx4
// window overflow would become a double exception.
// Set PS.UM (bit 5) so level-1 exceptions route to User vector.
rsr.ps a2
movi a3, ~0x1F
and a2, a2, a3
movi a3, 0x20
or a2, a2, a3
wsr.ps a2
rsync
// ---- 4. Configure flash cache and MMU ----
//
// ROM function calls use callx4 (windowed ABI):
// a4 = target address (overwritten with return addr by call mechanism)
// a5 = stack pointer for callee (becomes callee's a1 via entry)
// a6 = first argument (becomes callee's a2)
// a7 = second argument (becomes callee's a3)
// a8 = third argument (becomes callee's a4)
// Registers a0-a3 are preserved across callx4; a4-a11 may be clobbered.
// Phase A: Configure cache modes (required for cache hardware to function).
// Without this, the cache doesn't know its size/associativity/line-size
// and cannot service flash accesses.
// 4a. Configure ICache mode: 16KB, 8-way, 32-byte line
movi a6, 0x4000 // cache_size = 16KB
movi a7, 8 // ways = 8
movi a8, 32 // line_size = 32
mov a5, a1
l32r a4, .Lrom_config_icache
callx4 a4
// 4b. Suspend DCache before configuring it
mov a5, a1
l32r a4, .Lrom_suspend_dcache
callx4 a4
// 4c. Configure DCache mode: 32KB, 8-way, 32-byte line
movi a6, 0x8000 // cache_size = 32KB
movi a7, 8 // ways = 8
movi a8, 32 // line_size = 32
mov a5, a1
l32r a4, .Lrom_config_dcache
callx4 a4
// 4d. Resume DCache
movi a6, 0
mov a5, a1
l32r a4, .LCache_Resume_DCache
callx4 a4
// Phase B: Map flash pages into MMU.
// 4e. Disable ICache
mov a5, a1
l32r a4, .LCache_Disable_ICache
callx4 a4
// 4f. Disable DCache
mov a5, a1
l32r a4, .LCache_Disable_DCache
callx4 a4
// 4g. Initialize MMU (resets all 512 entries to invalid = 0x4000)
mov a5, a1
l32r a4, .LCache_MMU_Init
callx4 a4
// 4h. Set IDROM MMU size: even 256/256 split.
// Each entry is 4 bytes, so 256 entries = 0x400 bytes per region.
movi a6, 0x400 // irom_mmu_size (256 entries × 4 bytes)
movi a7, 0x400 // drom_mmu_size (256 entries × 4 bytes)
mov a5, a1
l32r a4, .LCache_Set_IDROM_MMU_Size
callx4 a4
// 4i. Map flash pages for IROM and DROM using identity mapping.
// MMU table at 0x600C5000: entries 0-255 = ICache, 256-511 = DCache.
// Entry value N = flash page N (SOC_MMU_VALID = 0 on S3).
// Each 64KB page needs one 4-byte entry.
//
// IROM: map pages 0..N where N = (_irom_end - 0x42000000) >> 16
// DROM: map pages 0..M where M = (_drom_end - 0x3C000000) >> 16
l32r a8, .Lmmu_table_base // a8 = 0x600C5000
// --- IROM pages ---
l32r a2, .Lirom_end // a2 = _irom_end (VMA in 0x42xxxxxx)
l32r a3, .Lirom_base // a3 = 0x42000000
sub a2, a2, a3 // a2 = byte offset past IROM base
srli a2, a2, 16 // a2 = last page index
addi a2, a2, 1 // a2 = number of pages to map
movi a9, 0 // a9 = page counter (and entry value)
mov a10, a8 // a10 = current MMU entry pointer
.Lirom_loop:
s32i a9, a10, 0
addi a9, a9, 1
addi a10, a10, 4
blt a9, a2, .Lirom_loop
// --- DROM pages ---
l32r a2, .Ldrom_end // a2 = _drom_end (VMA in 0x3Cxxxxxx)
l32r a3, .Ldrom_base // a3 = 0x3C000000
sub a2, a2, a3 // a2 = byte offset past DROM base
srli a2, a2, 16 // a2 = last page index
addi a2, a2, 1 // a2 = number of pages to map
movi a9, 0 // a9 = page counter (and entry value)
addmi a10, a8, 0x400 // a10 = 0x600C5400 (DCache entry 256)
.Ldrom_loop:
s32i a9, a10, 0
addi a9, a9, 1
addi a10, a10, 4
blt a9, a2, .Ldrom_loop
memw
// 4j. Clear bus-shut bits so core 0 can access ICache and DCache buses.
l32r a8, .Licache_ctrl1_reg // 0x600C4064
movi a9, 0
s32i a9, a8, 0 // Clear all ICACHE_CTRL1 shut bits
l32r a8, .Ldcache_ctrl1_reg // 0x600C4004
s32i a9, a8, 0 // Clear all DCACHE_CTRL1 shut bits
memw
// 4k. Enable ICache (arg: autoload = 0)
movi a6, 0
mov a5, a1
l32r a4, .LCache_Enable_ICache
callx4 a4
// 4l. Enable DCache (arg: autoload = 0)
movi a6, 0
mov a5, a1
l32r a4, .LCache_Enable_DCache
callx4 a4
// Flush instruction pipeline so new cache/MMU config takes effect.
isync
// ---- 5. Jump to main (in IROM) ----
// Re-clear PS.EXCM in case ROM calls changed processor state.
rsr.ps a2
movi a3, ~0x1F
and a2, a2, a3
movi a3, 0x20
or a2, a2, a3
wsr.ps a2
rsync
mov a5, a1
l32r a4, .Lmain_addr
callx4 a4
// If main returns, loop forever.
1: j 1b
// -----------------------------------------------------------------------
// tinygo_scanCurrentStack Spill all Xtensa register windows to the
// stack, then call tinygo_scanstack(sp) so the conservative GC can
// discover live heap pointers that are currently in physical registers.
//
// On RISC-V / ARM the equivalent function pushes callee-saved registers
// before the call. On Xtensa windowed ABI the same effect is achieved
// by forcing hardware window-overflow for every occupied pane: each
// overflow saves the four registers in that pane to the stack frame
// pointed to by the pane's a1 (sp). After all panes are flushed, a
// scan from the current sp to stackTop covers every live value.
// -----------------------------------------------------------------------
.section .text.tinygo_scanCurrentStack
.global tinygo_scanCurrentStack
tinygo_scanCurrentStack:
entry a1, 48
// Disable interrupts while flushing register windows.
rsr a4, PS
s32i a4, a1, 0 // save PS for later restore
rsil a4, 3 // XCHAL_EXCM_LEVEL
// Flush all register windows using recursive call4.
// For NAREG=64 (16 panes), 15 recursive levels cover all panes
// except the current one (which is kept active).
movi a6, 15
call4 .Lscan_spill
// Restore interrupts.
l32i a4, a1, 0
wsr.ps a4
rsync
// Pass current sp to tinygo_scanstack.
// call4 maps caller's a5callee's a1 (stack ptr for callee's entry)
// and caller's a6callee's a2 (first argument = sp).
mov a5, a1 // callee's a1 = valid stack pointer
mov a6, a1 // callee's a2 = sp argument
call4 tinygo_scanstack
retw
.balign 4
.Lscan_spill:
entry a1, 16
beqz a2, .Lscan_spill_done
addi a2, a2, -1
mov a6, a2
call4 .Lscan_spill
.Lscan_spill_done:
retw
-60
View File
@@ -85,9 +85,6 @@ var (
SIO = (*SIO_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0134))) SIO = (*SIO_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0134)))
INTERRUPT = (*INTERRUPT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0200))) INTERRUPT = (*INTERRUPT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0200)))
// BIOS interrupt flags
BIOS_IF = (*volatile.Register16)(unsafe.Pointer(uintptr(0x03007FF8)))
) )
// Main memory sections // Main memory sections
@@ -828,60 +825,3 @@ const (
OAMOBJ_ATT2_PB_Pos = 0xC OAMOBJ_ATT2_PB_Pos = 0xC
OAMOBJ_ATT2_PB_Msk = 0xF OAMOBJ_ATT2_PB_Msk = 0xF
) )
// Constants for SOUND: sound control
const (
SSW_INC = 0x0 // Increasing sweep rate
SSW_DEC = 0x0008 // Decreasing sweep rate
SSW_OFF = 0x0008 // Disable sweep altogether
SSQR_DUTY1_8 = 0x0 // 12.5% duty cycle (#-------)
SSQR_DUTY1_4 = 0x0040 // 25% duty cycle (##------)
SSQR_DUTY1_2 = 0x0080 // 50% duty cycle (####----)
SSQR_DUTY3_4 = 0x00C0 // 75% duty cycle (######--) Equivalent to 25%
SSQR_INC = 0x0 // Increasing volume
SSQR_DEC = 0x0800 // Decreasing volume
SFREQ_HOLD = 0x0 // Continuous play
SFREQ_TIMED = 0x4000 // Timed play
SFREQ_RESET = 0x8000 // Reset sound
SDMG_SQR1 = 0x01
SDMG_SQR2 = 0x02
SDMG_WAVE = 0x04
SDMG_NOISE = 0x08
SDMG_LSQR1 = 0x0100 // Enable channel 1 on left
SDMG_LSQR2 = 0x0200 // Enable channel 2 on left
SDMG_LWAVE = 0x0400 // Enable channel 3 on left
SDMG_LNOISE = 0x0800 // Enable channel 4 on left
SDMG_RSQR1 = 0x1000 // Enable channel 1 on right
SDMG_RSQR2 = 0x2000 // Enable channel 2 on right
SDMG_RWAVE = 0x4000 // Enable channel 3 on right
SDMG_RNOISE = 0x8000 // Enable channel 4 on right
SDS_DMG25 = 0x0 // Tone generators at 25% volume
SDS_DMG50 = 0x0001 // Tone generators at 50% volume
SDS_DMG100 = 0x0002 // Tone generators at 100% volume
SDS_A50 = 0x0 // Direct Sound A at 50% volume
SDS_A100 = 0x0004 // Direct Sound A at 100% volume
SDS_B50 = 0x0 // Direct Sound B at 50% volume
SDS_B100 = 0x0008 // Direct Sound B at 100% volume
SDS_AR = 0x0100 // Enable Direct Sound A on right
SDS_AL = 0x0200 // Enable Direct Sound A on left
SDS_ATMR0 = 0x0 // Direct Sound A to use timer 0
SDS_ATMR1 = 0x0400 // Direct Sound A to use timer 1
SDS_ARESET = 0x0800 // Reset FIFO of Direct Sound A
SDS_BR = 0x1000 // Enable Direct Sound B on right
SDS_BL = 0x2000 // Enable Direct Sound B on left
SDS_BTMR0 = 0x0 // Direct Sound B to use timer 0
SDS_BTMR1 = 0x4000 // Direct Sound B to use timer 1
SDS_BRESET = 0x8000 // Reset FIFO of Direct Sound B
SSTAT_SQR1 = 0x0001 // (R) Channel 1 status
SSTAT_SQR2 = 0x0002 // (R) Channel 2 status
SSTAT_WAVE = 0x0004 // (R) Channel 3 status
SSTAT_NOISE = 0x0008 // (R) Channel 4 status
SSTAT_DISABLE = 0 // Disable sound
SSTAT_ENABLE = 0x0080 // Enable sound. NOTE: enable before using any other sound regs
)

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