mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-01 02:09:06 +00:00
Compare commits
5 Commits
esp32c6-espradio
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| bdc4a21af0 | |||
| 2761414777 | |||
| 7d4b42db83 | |||
| fc0673430d | |||
| 61c315cbfb |
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Print the CHANGELOG.md entry for one version, to use as release notes.
|
||||||
|
# The file uses a setext heading: the bare version, then a line of dashes.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
version="$1"
|
||||||
|
if [ -z "$version" ]; then
|
||||||
|
echo "usage: $0 <version>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
notes=$(awk -v version="$version" '
|
||||||
|
found {
|
||||||
|
if ($0 ~ /^---+$/ && previous != "") { previous = ""; exit }
|
||||||
|
if (previous != "") print previous
|
||||||
|
previous = $0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
$0 ~ /^---+$/ && previous == version {
|
||||||
|
found = 1
|
||||||
|
previous = ""
|
||||||
|
next
|
||||||
|
}
|
||||||
|
{ previous = $0 }
|
||||||
|
END { if (found && previous != "") print previous }
|
||||||
|
' CHANGELOG.md)
|
||||||
|
|
||||||
|
if [ -z "$notes" ]; then
|
||||||
|
echo "no CHANGELOG.md entry for version $version" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$notes"
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# Publish a GitHub release from the artifacts that CI already built.
|
||||||
|
#
|
||||||
|
# The Linux, macOS and Windows workflows build every file that a release needs
|
||||||
|
# when the release branch is pushed. This workflow collects the artifacts of
|
||||||
|
# those runs for the tagged commit, so what ships is what was tested.
|
||||||
|
#
|
||||||
|
# The release is a draft, so the notes can be reviewed before publication.
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'Tag to release, for example v0.42.0'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: release-${{ inputs.tag || github.ref_name }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
actions: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
GH_REPO: ${{ github.repository }}
|
||||||
|
TAG: ${{ inputs.tag || github.ref_name }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.tag || github.ref_name }}
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Read the version
|
||||||
|
id: version
|
||||||
|
# The release file names come from goenv/version.go, not from the tag,
|
||||||
|
# so the two must agree.
|
||||||
|
run: |
|
||||||
|
version=$(./.github/workflows/tinygo-extract-version.sh | cut -d= -f2-)
|
||||||
|
case "$version" in
|
||||||
|
*-dev)
|
||||||
|
echo "::error::goenv/version.go has development version $version"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [ "v$version" != "$TAG" ]; then
|
||||||
|
echo "::error::tag $TAG does not match version $version in goenv/version.go"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Wait for the CI runs of this commit
|
||||||
|
id: runs
|
||||||
|
# A pull request run has the merge commit as its head, so look at push
|
||||||
|
# runs only.
|
||||||
|
run: |
|
||||||
|
sha=$(git rev-parse HEAD)
|
||||||
|
for workflow in linux.yml build-macos.yml windows.yml; do
|
||||||
|
id=
|
||||||
|
for _ in $(seq 20); do
|
||||||
|
id=$(gh run list --workflow "$workflow" --commit "$sha" --event push --limit 1 --json databaseId --jq '.[0].databaseId')
|
||||||
|
if [ -n "$id" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "waiting for $workflow to start on $sha"
|
||||||
|
sleep 30
|
||||||
|
done
|
||||||
|
if [ -z "$id" ]; then
|
||||||
|
echo "::error::no $workflow run for commit $sha"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "$workflow: run $id"
|
||||||
|
gh run watch "$id" --exit-status > /dev/null || true
|
||||||
|
conclusion=$(gh run view "$id" --json conclusion --jq .conclusion)
|
||||||
|
if [ "$conclusion" != "success" ]; then
|
||||||
|
echo "::error::$workflow run $id concluded with $conclusion"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
case "$workflow" in
|
||||||
|
linux.yml) echo "linux=$id" >> "$GITHUB_OUTPUT" ;;
|
||||||
|
build-macos.yml) echo "macos=$id" >> "$GITHUB_OUTPUT" ;;
|
||||||
|
windows.yml) echo "windows=$id" >> "$GITHUB_OUTPUT" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
# The build jobs upload with `archive: false`, so the artifact is the
|
||||||
|
# release file itself. skip-decompress keeps it that way. The Windows
|
||||||
|
# release is a .zip, which a download would otherwise unpack.
|
||||||
|
- name: Download the Linux artifacts
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
run-id: ${{ steps.runs.outputs.linux }}
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
path: artifacts
|
||||||
|
skip-decompress: true
|
||||||
|
- name: Download the macOS artifacts
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
run-id: ${{ steps.runs.outputs.macos }}
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
path: artifacts
|
||||||
|
skip-decompress: true
|
||||||
|
- name: Download the Windows artifacts
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
run-id: ${{ steps.runs.outputs.windows }}
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
path: artifacts
|
||||||
|
skip-decompress: true
|
||||||
|
- name: Collect the release files
|
||||||
|
# A build that stopped uploading must not give a half complete release,
|
||||||
|
# so list the files that are expected. The search is by file name, not
|
||||||
|
# by artifact name, because the artifact names are not uniform.
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
version=$VERSION
|
||||||
|
mkdir -p dist
|
||||||
|
missing=0
|
||||||
|
for file in \
|
||||||
|
"tinygo$version.linux-amd64.tar.gz" "tinygo_${version}_amd64.deb" \
|
||||||
|
"tinygo$version.linux-arm.tar.gz" "tinygo_${version}_armhf.deb" \
|
||||||
|
"tinygo$version.linux-arm64.tar.gz" "tinygo_${version}_arm64.deb" \
|
||||||
|
"tinygo$version.darwin-amd64.tar.gz" \
|
||||||
|
"tinygo$version.darwin-arm64.tar.gz" \
|
||||||
|
"tinygo$version.windows-amd64.zip"; do
|
||||||
|
found=$(find artifacts -type f -name "$file" | head -1)
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
echo "::error::missing release file $file"
|
||||||
|
missing=1
|
||||||
|
else
|
||||||
|
mv "$found" "dist/$file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
ls -l dist
|
||||||
|
exit $missing
|
||||||
|
- name: Extract the release notes
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: ./.github/workflows/extract-changelog.sh "$VERSION" > notes.md
|
||||||
|
- name: Create the draft release
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
version=$VERSION
|
||||||
|
set --
|
||||||
|
case "$version" in
|
||||||
|
*-*) set -- --prerelease ;;
|
||||||
|
esac
|
||||||
|
gh release create "$TAG" --draft --verify-tag "$@" \
|
||||||
|
--title "$version" \
|
||||||
|
--notes-file notes.md \
|
||||||
|
dist/*
|
||||||
+32
@@ -123,3 +123,35 @@ the following command (for example in ~/lib):
|
|||||||
TinyGo will get extracted to a `tinygo` directory. You can then call it with:
|
TinyGo will get extracted to a `tinygo` directory. You can then call it with:
|
||||||
|
|
||||||
./tinygo/bin/tinygo
|
./tinygo/bin/tinygo
|
||||||
|
|
||||||
|
## Publish a release
|
||||||
|
|
||||||
|
The `Release` workflow (`.github/workflows/release.yml`) publishes releases. It
|
||||||
|
does not build anything. The Linux, macOS and Windows workflows already build
|
||||||
|
every file that a release needs when the `release` branch is pushed, so the
|
||||||
|
release workflow collects the artifacts of those runs for the tagged commit.
|
||||||
|
What ships is what was tested.
|
||||||
|
|
||||||
|
1. On the `dev` branch, set `const version` in `goenv/version.go` to the new
|
||||||
|
version (without a `v` prefix), and add the entry to `CHANGELOG.md`.
|
||||||
|
2. Merge `dev` into the `release` branch.
|
||||||
|
3. Tag that commit and push the tag:
|
||||||
|
|
||||||
|
git tag v0.42.0
|
||||||
|
git push origin v0.42.0
|
||||||
|
|
||||||
|
The tag must be `v` plus the version in `goenv/version.go`, because the
|
||||||
|
release file names come from that constant.
|
||||||
|
4. The workflow waits for the Linux, macOS and Windows runs of the tagged
|
||||||
|
commit, collects their nine files, and creates a **draft** release. The
|
||||||
|
release notes come from the `CHANGELOG.md` entry for that version.
|
||||||
|
5. Review the draft release and publish it.
|
||||||
|
6. On the `dev` branch, set `goenv/version.go` to the next `-dev` version.
|
||||||
|
|
||||||
|
To release again after a failure, delete the draft release and start the
|
||||||
|
workflow from the Actions tab with the tag as its input.
|
||||||
|
|
||||||
|
GitHub keeps a SHA-256 digest of every published file. The digest is not shown
|
||||||
|
on the release page, but it can be printed with:
|
||||||
|
|
||||||
|
gh release view v0.42.0 --json assets --jq '.assets[] | "\(.digest) \(.name)"'
|
||||||
|
|||||||
+160
@@ -1,3 +1,163 @@
|
|||||||
|
0.42.0
|
||||||
|
---
|
||||||
|
* **general**
|
||||||
|
- all: add LLVM 22 support, and support LLVM 19 and LLVM 20 on Fedora 43
|
||||||
|
- all: build and test using Go 1.27, and raise the max supported Go version to 1.27
|
||||||
|
- all: modernize and clean up code with Go 1.24+ in mind (#5489, #5498)
|
||||||
|
- all: use unsafe.SliceData where appropriate
|
||||||
|
- all: update golang.org/x/tools and go-llvm
|
||||||
|
- cli: add basic probe-rs support
|
||||||
|
- cli: clarify the runtime.alloc linker error with -gc=none
|
||||||
|
- main: allow the -o flag to point to a directory
|
||||||
|
- main: make the -monitor flag on flash respect the port
|
||||||
|
- main: update to espflasher 0.8.0 with fixes for esp32c3 and esp32s3
|
||||||
|
- cgo: add CGO_CFLAGS support (#5453)
|
||||||
|
- version: update to 0.42.0 for the new dev cycle
|
||||||
|
- docs: add agents.md guideline for use of ASD-STE100 (#5566)
|
||||||
|
* **compiler**
|
||||||
|
- compiler, runtime: make runtime, map, and channel panics recoverable
|
||||||
|
- compiler, runtime: support recover on riscv64
|
||||||
|
- compiler, runtime, reflect: generate type-specific hash/equal (#5359)
|
||||||
|
- support Go 1.27 generic methods via the x/tools upgrade
|
||||||
|
- canonicalize generic instance and method signature identities
|
||||||
|
- disambiguate function-local named types and generic instance link names (#5336)
|
||||||
|
- exclude generic methods from runtime method sets
|
||||||
|
- support file-level //go:linkname directives and the //go:linknamestd pragma
|
||||||
|
- add the //go:noheap pragma
|
||||||
|
- pass large aggregates by pointer
|
||||||
|
- use LLVM intrinsics for math trig operations
|
||||||
|
- optimize zero-sized allocations
|
||||||
|
- consistently pass layout and alignment to createAlloc
|
||||||
|
- handle nested unsigned shift being untyped after type resolution (#5497)
|
||||||
|
- store the defer list head in the defer frame and centralize deferred call records
|
||||||
|
- centralize SSA loads, stores, result handling, and LLVM function type construction
|
||||||
|
- transform, compiler: support the captures(none) attribute of LLVM 21
|
||||||
|
- compiler: make composite map hashes order dependent
|
||||||
|
* **core**
|
||||||
|
- reflect: add Type.ConvertibleTo and complex, rune, and integer string conversions
|
||||||
|
- reflect: implement MakeChan
|
||||||
|
- reflect: add missing iterator methods
|
||||||
|
- reflect, reflectlite: make IsRO and MakeRO package methods
|
||||||
|
- sync: add Map.CompareAndSwap and Map.CompareAndDelete
|
||||||
|
- sync: fix deadlock in the Map.Range callback
|
||||||
|
- os, syscall: add Statfs and Fstatfs stubs and Getpagesize for non-hosted targets
|
||||||
|
- os: add File.Chown on the unix path
|
||||||
|
- runtime, syscall, internal/poll, os: wasip1 poll_oneoff scheduler integration and net.FileListener (#5386)
|
||||||
|
- runtime, testing: support Goexit, SkipNow, and FailNow
|
||||||
|
- syscall: remove sliceHeader, use unsafe.SliceData more
|
||||||
|
- builder, cgo, syscall: replace fixed-size array casts with unsafe.Slice
|
||||||
|
- builder, loader: fix -ldflags -X not overriding variables with default values
|
||||||
|
- builder: build SSA before compiling packages
|
||||||
|
- builder: increase the stack size margin for automatic stack allocation
|
||||||
|
- builder: do not count non-writable SHT_NOBITS sections as RAM or bss
|
||||||
|
- builder: link stack probes on Windows amd64 and arm64, and add chkstk2.S for windows/386
|
||||||
|
- builder: add strlen to the wasm builtins
|
||||||
|
- builder: retry cached archive renames on Windows (#5462)
|
||||||
|
- loader: avoid a race condition when loading the package list, and skip object resolution
|
||||||
|
- interp: bail out of loops that iterate too many times (#5395)
|
||||||
|
- interp: fix partial store aliasing and avoid repeated object clones
|
||||||
|
- interp: defer out-of-bounds loads to runtime instead of crashing
|
||||||
|
- interp: mark pointers in aggregate call operands as external
|
||||||
|
- interp: fix switch-instruction handling for the new case-value API of LLVM 22
|
||||||
|
- transform: follow returned pointer and aggregate alloc aliases
|
||||||
|
- transform: add -print-allocs-cover and restore the -print-allocs reason output
|
||||||
|
- device: add device/uefi and device/amd64
|
||||||
|
- wasm: patch wasm_exec.js and wasm_exec_node.js from Go 1.18+ (#5483)
|
||||||
|
* **net**
|
||||||
|
- update the net module with a roundtrip fix for js/wasm
|
||||||
|
* **runtime**
|
||||||
|
- make divide-by-zero and nil dereference panics recoverable
|
||||||
|
- add a Windows vectored exception handler for recoverable panics
|
||||||
|
- make Goexit exit host threads, and encode a pending Goexit in the panic state
|
||||||
|
- make out-of-memory and fatal failures unrecoverable
|
||||||
|
- improve the hardfault handler and stack reporting on Cortex-M
|
||||||
|
- prevent timer starvation in the cores scheduler
|
||||||
|
- do not access the timer queue outside of the lock
|
||||||
|
- fix ticker not stopping when Stop races with its callback (#5487)
|
||||||
|
- wake channel waiters after releasing locks (#5513)
|
||||||
|
- implement SetFinalizer and run syscall/js finalizers without a manual GC (#5545)
|
||||||
|
- implement MemStats.NumGC
|
||||||
|
- add runtime.fastrandn (#5502)
|
||||||
|
- make arrays and struct field hashes order dependent
|
||||||
|
- add critical-section fallbacks for atomic And and Or
|
||||||
|
- gc: pause all cores before scanning the stack and globals
|
||||||
|
- gc: correct the old size calculation in block realloc
|
||||||
|
- gc: correct the leaking allocator bounds and overflow checks
|
||||||
|
- gc: move objHeader to the end of the block header
|
||||||
|
- fix the leaking GC build with the cores scheduler
|
||||||
|
- rp2040: fix -gc=leaking and -gc=none
|
||||||
|
- rp2: handle the RP2350 shared FIFO IRQ for GC (#5482)
|
||||||
|
- esp32c6: select the 80MHz PLL as the TIMG0 timer clock source
|
||||||
|
- split baremetal memory setup and the Windows PE globals scan for UEFI (#5360, #5361)
|
||||||
|
* **machine**
|
||||||
|
- usb: support bidirectional endpoints by dynamic registration on RP2, SAMD21/51, and nRF52840 (#5447)
|
||||||
|
- usb: generate endpoint descriptors dynamically
|
||||||
|
- usb: implement endpoint stall for nRF52840
|
||||||
|
- usb: fix a truncated string descriptor when the host requests a short maxLen (#5449)
|
||||||
|
- usb: add USBDevice.Attach and USBDevice.Detach (#5563)
|
||||||
|
- usb/cdc: fix the RP2 USB CDC TX race with the cores scheduler (#5391)
|
||||||
|
- add UART line inversion support (#5522)
|
||||||
|
- optimize RTT initialization
|
||||||
|
- device/arm: add ARM v7-M MPU support
|
||||||
|
- esp32: add interrupt support with vector table, timer alarm, and GPIO SetInterrupt
|
||||||
|
- esp32: add interrupt-based UART RX and fix the init order
|
||||||
|
- esp32: implement flash XIP (execute-in-place) support
|
||||||
|
- esp32: add ADC driver (#5595)
|
||||||
|
- esp32: fix pullup and pulldown on RTC GPIO pins
|
||||||
|
- esp32: remove dead code and fix GC root scanning
|
||||||
|
- esp32: configure UARTs to the specified pins and yield while waiting for the buffer
|
||||||
|
- esp32, esp32s3: fix the boot crash caused by the LLVM 22 lld l32r relocation bug
|
||||||
|
- esp32s3: fix register-window corruption under interrupt load
|
||||||
|
- esp32s3: add temperature reading
|
||||||
|
- esp32c6: add a minimal implementation with I2C and ADC support
|
||||||
|
- stm32: fix UART transmission, baud rate, and interrupt handling
|
||||||
|
- stm32: add an OTG FS USB driver for F4 and F7
|
||||||
|
- stm32: add STM32H7 and NUCLEO-H753ZI support
|
||||||
|
- stm32: add support for the STM32U031 chip
|
||||||
|
- stm32: make the HSE crystal frequency selectable
|
||||||
|
- stm32u5: configure the system clock to 160 MHz
|
||||||
|
- nrf: avoid a too high priority interrupt on SoftDevice
|
||||||
|
- rp2: allow SPI transmit-only without SDI (#5437)
|
||||||
|
- rp2: clear the USB buffer status before the endpoint handlers
|
||||||
|
- rp2350: fix the ROM CS control for the RP2350 ROM code
|
||||||
|
- add GP aliases for waveshare-rp2040-zero
|
||||||
|
- gba: add support for mGBA debugging
|
||||||
|
- gba: add bios interrupt flags and sound register constants (#5445)
|
||||||
|
* **targets**
|
||||||
|
- add minimal uefi target support with the LinkerFlavor option (#5452, #5465)
|
||||||
|
- uefi: add support for UEFI time and events, fix STOP newline conversion (#5549)
|
||||||
|
- uefi: add support for the tasks scheduler and make it the default (#5553)
|
||||||
|
- add Puya PY32F MCU support (#5106)
|
||||||
|
- add esp32s3-box-3 (#5388)
|
||||||
|
- add M5Stack Stamp-S3A (#5524)
|
||||||
|
- add Pimoroni Blinky 2350 and Badger 2350 (#5434)
|
||||||
|
- add the 'Plus' board variant of SeeedStudio XIAO nrf52840 (#5479)
|
||||||
|
- esp32: adjust memory usage, add DRAM1 sections, and export the symbols needed for wifi
|
||||||
|
- esp32c3: add the BT ROM functions to the linker
|
||||||
|
- esp32: add the espradio tag for convenience
|
||||||
|
- builder: fix esp32 XIP so large programs flash correctly, including QEMU image offsets
|
||||||
|
- wasm_exec.js: add runtime.getRandomData to the gojs imports, coerce memory offsets to unsigned, and reset _pendingEvent
|
||||||
|
* **libs**
|
||||||
|
- update macos-minimal-sdk to v0.1.0
|
||||||
|
* **build/test**
|
||||||
|
- ci: run the full smoke test once, and split the GNUmakefile (#5616)
|
||||||
|
- ci: publish a draft release from the artifacts that CI already built
|
||||||
|
- ci: stop the LLVM caches from being evicted
|
||||||
|
- ci: modify builds to use LLVM 22
|
||||||
|
- ci: add a check for compatibility with older Go and LLVM versions
|
||||||
|
- ci: add a job to make sure go.sum stays in sync with go.mod
|
||||||
|
- ci: re-add fmt-check, and remove the CircleCI configuration
|
||||||
|
- ci: adjust runner sizes for Linux, Windows, and macOS
|
||||||
|
- build: statically link the MinGW runtime in the LLVM tools on Windows
|
||||||
|
- Makefile: use ${LLVM_PROJECTDIR} during the copy phase
|
||||||
|
- GNUmakefile: disable DWARF compression for CGo objects, and update the stdlib test lists
|
||||||
|
- test: run ESP32 programs in QEMU
|
||||||
|
- test: support simavr 1.8+
|
||||||
|
- test: normalize LLVM IR when updating goldens
|
||||||
|
- test: convert TestBinarySize to a golden file test
|
||||||
|
- testdata: add regression tests for generic instances, generic aliases, and large aggregates
|
||||||
|
- test: skip flaky and Go 1.27 affected tests for now
|
||||||
|
|
||||||
0.41.1
|
0.41.1
|
||||||
---
|
---
|
||||||
* **machine**
|
* **machine**
|
||||||
|
|||||||
@@ -43,11 +43,11 @@ var libWasmBuiltins = Library{
|
|||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
||||||
librarySources: func(target string, _ bool) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
|
// Memory builtins needed for LLVM intrinsics and library calls.
|
||||||
// llvm.memset.* LLVM intrinsics.
|
|
||||||
"libc-top-half/musl/src/string/memcpy.c",
|
"libc-top-half/musl/src/string/memcpy.c",
|
||||||
"libc-top-half/musl/src/string/memmove.c",
|
"libc-top-half/musl/src/string/memmove.c",
|
||||||
"libc-top-half/musl/src/string/memset.c",
|
"libc-top-half/musl/src/string/memset.c",
|
||||||
|
"libc-top-half/musl/src/string/strlen.c",
|
||||||
|
|
||||||
// exp, exp2, and log are needed for LLVM math builtin functions
|
// exp, exp2, and log are needed for LLVM math builtin functions
|
||||||
// like llvm.exp.*.
|
// like llvm.exp.*.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
var libVersions = map[string]int{
|
var libVersions = map[string]int{
|
||||||
"musl": 3,
|
"musl": 3,
|
||||||
"bdwgc": 2,
|
"bdwgc": 2,
|
||||||
|
"wasmbuiltins": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config keeps all configuration affecting the build in a single struct.
|
// Config keeps all configuration affecting the build in a single struct.
|
||||||
|
|||||||
+5
-3
@@ -417,6 +417,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
|
multiplier := llvm.ConstInt(b.ctx.Int32Type(), 31, false)
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 0; i < keyType.NumFields(); i++ {
|
for i := 0; i < keyType.NumFields(); i++ {
|
||||||
if keyType.Field(i).Name() == "_" {
|
if keyType.Field(i).Name() == "_" {
|
||||||
@@ -430,7 +431,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
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}, "")
|
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||||
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
|
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
|
||||||
hash = b.CreateXor(hash, fieldHash, "")
|
hash = b.CreateXor(b.CreateMul(hash, multiplier, ""), fieldHash, "")
|
||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
@@ -445,6 +446,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
if arrayLen == 0 {
|
if arrayLen == 0 {
|
||||||
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
}
|
}
|
||||||
|
multiplier := llvm.ConstInt(b.ctx.Int32Type(), 31, false)
|
||||||
if arrayLen <= hashArrayUnrollLimit {
|
if arrayLen <= hashArrayUnrollLimit {
|
||||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
@@ -452,7 +454,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
||||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||||
hash = b.CreateXor(hash, elemHash, "")
|
hash = b.CreateXor(b.CreateMul(hash, multiplier, ""), elemHash, "")
|
||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
@@ -471,7 +473,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
|
|
||||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
|
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
|
||||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||||
newHash := b.CreateXor(phiHash, elemHash, "")
|
newHash := b.CreateXor(b.CreateMul(phiHash, multiplier, ""), elemHash, "")
|
||||||
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||||
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
||||||
b.CreateCondBr(cond, loopBody, loopDone)
|
b.CreateCondBr(cond, loopBody, loopDone)
|
||||||
|
|||||||
Vendored
+20
@@ -12,6 +12,11 @@ type nestedPadding struct {
|
|||||||
i int
|
i int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringStruct struct {
|
||||||
|
a string
|
||||||
|
b string
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func testZeroGet(m map[hasPadding]int, s hasPadding) int {
|
func testZeroGet(m map[hasPadding]int, s hasPadding) int {
|
||||||
return m[s]
|
return m[s]
|
||||||
@@ -32,6 +37,21 @@ func testZeroArraySet(m map[[2]hasPadding]int, s [2]hasPadding) {
|
|||||||
m[s] = 5
|
m[s] = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func makeStringStructMap() map[stringStruct]int {
|
||||||
|
return make(map[stringStruct]int)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func makeShortStringArrayMap() map[[2]string]int {
|
||||||
|
return make(map[[2]string]int)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func makeLongStringArrayMap() map[[5]string]int {
|
||||||
|
return make(map[[5]string]int)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+147
@@ -4,6 +4,7 @@ target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-n
|
|||||||
target triple = "wasm32-unknown-wasi"
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
%main.hasPadding = type { i1, i32, i1 }
|
%main.hasPadding = type { i1, i32, i1 }
|
||||||
|
%runtime._string = type { ptr, i32 }
|
||||||
|
|
||||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #0
|
||||||
|
|
||||||
@@ -97,6 +98,152 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define hidden ptr @main.makeStringStructMap(ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%stackalloc = alloca i8, align 1
|
||||||
|
%0 = call ptr @runtime.hashmapMakeGeneric(i32 16, i32 4, i32 8, ptr null, ptr nonnull @"hashmapKeyHash.struct{string; string}", ptr null, ptr nonnull @"hashmapKeyEqual.struct{string; string}", ptr undef) #4
|
||||||
|
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #4
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i32 @"hashmapKeyHash.struct{string; string}"(ptr %0, i32 %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
||||||
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
|
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
||||||
|
%5 = mul i32 %hash, 31
|
||||||
|
%6 = xor i32 %5, %hash1
|
||||||
|
ret i32 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @runtime.hashmapStringPtrHash(ptr, i32, i32, ptr) #0
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i1 @"hashmapKeyEqual.struct{string; string}"(ptr %0, ptr %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%x.str.unpack = load ptr, ptr %0, align 4
|
||||||
|
%x.str.elt4 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
|
%x.str.unpack5 = load i32, ptr %x.str.elt4, align 4
|
||||||
|
%y.str.unpack = load ptr, ptr %1, align 4
|
||||||
|
%y.str.elt7 = getelementptr inbounds nuw i8, ptr %1, i32 4
|
||||||
|
%y.str.unpack8 = load i32, ptr %y.str.elt7, align 4
|
||||||
|
%eq = call i1 @runtime.stringEqual(ptr %x.str.unpack, i32 %x.str.unpack5, ptr %y.str.unpack, i32 %y.str.unpack8, ptr undef) #4
|
||||||
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
|
%5 = getelementptr inbounds nuw i8, ptr %1, i32 8
|
||||||
|
%x.str1.unpack = load ptr, ptr %4, align 4
|
||||||
|
%x.str1.elt10 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||||
|
%x.str1.unpack11 = load i32, ptr %x.str1.elt10, align 4
|
||||||
|
%y.str2.unpack = load ptr, ptr %5, align 4
|
||||||
|
%y.str2.elt13 = getelementptr inbounds nuw i8, ptr %1, i32 12
|
||||||
|
%y.str2.unpack14 = load i32, ptr %y.str2.elt13, align 4
|
||||||
|
%eq3 = call i1 @runtime.stringEqual(ptr %x.str1.unpack, i32 %x.str1.unpack11, ptr %y.str2.unpack, i32 %y.str2.unpack14, ptr undef) #4
|
||||||
|
%6 = and i1 %eq, %eq3
|
||||||
|
ret i1 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i1 @runtime.stringEqual(ptr readonly, i32, ptr readonly, i32, ptr) #0
|
||||||
|
|
||||||
|
declare ptr @runtime.hashmapMakeGeneric(i32, i32, i32, ptr, ptr, ptr, ptr, ptr) #0
|
||||||
|
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define hidden ptr @main.makeShortStringArrayMap(ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%stackalloc = alloca i8, align 1
|
||||||
|
%0 = call ptr @runtime.hashmapMakeGeneric(i32 16, i32 4, i32 8, ptr null, ptr nonnull @"hashmapKeyHash.[2]string", ptr null, ptr nonnull @"hashmapKeyEqual.[2]string", ptr undef) #4
|
||||||
|
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #4
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i32 @"hashmapKeyHash.[2]string"(ptr %0, i32 %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
||||||
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
|
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
||||||
|
%5 = mul i32 %hash, 31
|
||||||
|
%6 = xor i32 %5, %hash1
|
||||||
|
ret i32 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i1 @"hashmapKeyEqual.[2]string"(ptr %0, ptr %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
%x.str.unpack = load ptr, ptr %0, align 4
|
||||||
|
%x.str.elt4 = getelementptr inbounds nuw i8, ptr %0, i32 4
|
||||||
|
%x.str.unpack5 = load i32, ptr %x.str.elt4, align 4
|
||||||
|
%y.str.unpack = load ptr, ptr %1, align 4
|
||||||
|
%y.str.elt7 = getelementptr inbounds nuw i8, ptr %1, i32 4
|
||||||
|
%y.str.unpack8 = load i32, ptr %y.str.elt7, align 4
|
||||||
|
%eq = call i1 @runtime.stringEqual(ptr %x.str.unpack, i32 %x.str.unpack5, ptr %y.str.unpack, i32 %y.str.unpack8, ptr undef) #4
|
||||||
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
|
%5 = getelementptr inbounds nuw i8, ptr %1, i32 8
|
||||||
|
%x.str1.unpack = load ptr, ptr %4, align 4
|
||||||
|
%x.str1.elt10 = getelementptr inbounds nuw i8, ptr %0, i32 12
|
||||||
|
%x.str1.unpack11 = load i32, ptr %x.str1.elt10, align 4
|
||||||
|
%y.str2.unpack = load ptr, ptr %5, align 4
|
||||||
|
%y.str2.elt13 = getelementptr inbounds nuw i8, ptr %1, i32 12
|
||||||
|
%y.str2.unpack14 = load i32, ptr %y.str2.elt13, align 4
|
||||||
|
%eq3 = call i1 @runtime.stringEqual(ptr %x.str1.unpack, i32 %x.str1.unpack11, ptr %y.str2.unpack, i32 %y.str2.unpack14, ptr undef) #4
|
||||||
|
%6 = and i1 %eq, %eq3
|
||||||
|
ret i1 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define hidden ptr @main.makeLongStringArrayMap(ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%stackalloc = alloca i8, align 1
|
||||||
|
%0 = call ptr @runtime.hashmapMakeGeneric(i32 40, i32 4, i32 8, ptr null, ptr nonnull @"hashmapKeyHash.[5]string", ptr null, ptr nonnull @"hashmapKeyEqual.[5]string", ptr undef) #4
|
||||||
|
call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #4
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i32 @"hashmapKeyHash.[5]string"(ptr %0, i32 %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
br label %hash.array.body
|
||||||
|
|
||||||
|
hash.array.body: ; preds = %hash.array.body, %entry
|
||||||
|
%i = phi i32 [ 0, %entry ], [ %7, %hash.array.body ]
|
||||||
|
%hash.acc = phi i32 [ 0, %entry ], [ %6, %hash.array.body ]
|
||||||
|
%4 = getelementptr inbounds nuw %runtime._string, ptr %0, i32 %i
|
||||||
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %4, i32 8, i32 %2, ptr undef) #4
|
||||||
|
%5 = mul i32 %hash.acc, 31
|
||||||
|
%6 = xor i32 %5, %hash
|
||||||
|
%7 = add nuw nsw i32 %i, 1
|
||||||
|
%8 = icmp samesign ult i32 %i, 4
|
||||||
|
br i1 %8, label %hash.array.body, label %hash.array.done
|
||||||
|
|
||||||
|
hash.array.done: ; preds = %hash.array.body
|
||||||
|
ret i32 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define linkonce_odr i1 @"hashmapKeyEqual.[5]string"(ptr %0, ptr %1, i32 %2, ptr %3) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
br label %eq.array.body
|
||||||
|
|
||||||
|
eq.array.body: ; preds = %eq.array.body, %entry
|
||||||
|
%i = phi i32 [ 0, %entry ], [ %6, %eq.array.body ]
|
||||||
|
%4 = getelementptr inbounds %runtime._string, ptr %0, i32 %i
|
||||||
|
%5 = getelementptr inbounds %runtime._string, ptr %1, i32 %i
|
||||||
|
%x.str.unpack = load ptr, ptr %4, align 4
|
||||||
|
%x.str.elt1 = getelementptr inbounds nuw i8, ptr %4, i32 4
|
||||||
|
%x.str.unpack2 = load i32, ptr %x.str.elt1, align 4
|
||||||
|
%y.str.unpack = load ptr, ptr %5, align 4
|
||||||
|
%y.str.elt4 = getelementptr inbounds nuw i8, ptr %5, i32 4
|
||||||
|
%y.str.unpack5 = load i32, ptr %y.str.elt4, align 4
|
||||||
|
%eq = call i1 @runtime.stringEqual(ptr %x.str.unpack, i32 %x.str.unpack2, ptr %y.str.unpack, i32 %y.str.unpack5, ptr undef) #4
|
||||||
|
%6 = add i32 %i, 1
|
||||||
|
%7 = icmp ult i32 %6, 5
|
||||||
|
%.not7 = and i1 %7, %eq
|
||||||
|
br i1 %.not7, label %eq.array.body, label %eq.array.done
|
||||||
|
|
||||||
|
eq.array.done: ; preds = %eq.array.body
|
||||||
|
ret i1 %eq
|
||||||
|
}
|
||||||
|
|
||||||
; 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 #1 {
|
||||||
entry:
|
entry:
|
||||||
|
|||||||
+1
-1
@@ -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.42.0"
|
||||||
|
|
||||||
// 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).
|
||||||
|
|||||||
@@ -576,6 +576,7 @@ ifneq ($(WASM), 0)
|
|||||||
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm examples/wasm/export
|
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm examples/wasm/export
|
||||||
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm examples/wasm/main
|
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm examples/wasm/main
|
||||||
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm-unknown examples/hello-wasm-unknown
|
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm-unknown examples/hello-wasm-unknown
|
||||||
|
$(TINYGO) build -size short -o $(SMOKE_OUT).wasm -target=wasm-unknown -opt=2 ./testdata/wasm-unknown-opt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
smoketest-flags: SMOKE_OUT = build/smoke/flags
|
smoketest-flags: SMOKE_OUT = build/smoke/flags
|
||||||
|
|||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
type value struct {
|
||||||
|
Field int
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport typeNameLength
|
||||||
|
func typeNameLength() uint32 {
|
||||||
|
return uint32(len(reflect.TypeOf(value{}).String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user