Compare commits

..

3 Commits

Author SHA1 Message Date
deadprogram ae9eb7e64e esp32c6: bind ROM data symbols to their ROM addresses
The ROM symbol tables were emitted entirely as PROVIDE(), which is right
for ROM functions but wrong for ROM data. Symbols like g_osi_funcs_p,
pTxRx, our_tx_eb and lmacConfMib_ptr are variables in RAM that mask ROM
code reads and writes at a fixed address; they are shared storage, not a
fallback implementation.

With PROVIDE(), a weak definition in the program wins and the program and
the mask ROM then use two different locations for the same variable.
g_osi_funcs_p hit exactly this: espradio declares it weak, so it resolved
to .bss while ROM code kept reading 0x4087ff6c, which nothing ever wrote.

Assign the 121 ROM data symbols unconditionally, as esp32c3.ld already
does for the same variables. Addresses verified identical to ESP-IDF's
esp32c6 ROM linker scripts.

Signed-off-by: Ron Evans <ron@hybridgroup.com>
2026-08-30 11:05:14 +02:00
deadprogram 6b53c58f92 esp32c6: fix .rodata flash mapping being off by a few bytes
The flash MMU maps 64kB pages, so a flash-mapped section is only read
correctly when its virtual address and its offset within the firmware
image agree modulo 64kB. targets/esp32c6.ld reproduces the image offset
in .rodata_dummy by accumulating the preceding segment sizes and headers,
which works only if the linker inserts no alignment padding between the
dummy and .rodata -- padding moves the virtual address without moving the
image offset.

lld gives .rodata 8-byte alignment, but the accumulated offset is only
4-byte aligned, so whenever the preceding segments happened to leave the
running offset at a 4-mod-8 boundary the whole of .rodata was mapped 4
bytes off. Every read of constant data then returned neighbouring bytes.

This is silent and looks like arbitrary memory corruption rather than a
mapping bug. It was found while bringing up WiFi: the blob rejected its
init config because the first field of a const struct read back as a code
pointer, and whether a given build was affected depended on unrelated code
size changes.

Pad .data, .iram and .text to a multiple of 8 so the running image offset
stays 8-aligned and matches, and add ASSERTs for both flash-mapped
sections so this cannot regress silently.

Signed-off-by: Ron Evans <ron@hybridgroup.com>
2026-08-30 10:36:44 +02:00
deadprogram a7626e87e9 esp32c6: prepare target for espradio WiFi support
The ESP32-C6 target was never built with a radio blob in mind. Three gaps
in targets/esp32c6.ld prevented espradio from linking or running:

- The Espressif WiFi/PHY libraries resolve ~245 internal symbols against
  the mask ROM. Only seven ROM symbols were defined. Add the ESP-IDF
  generated ROM interface tables (1201 symbols), all as PROVIDE() so any
  real definition in the program wins over the ROM copy.
- The .iram output section did not collect the blob IRAM sections
  (.wifi0iram, .wifirxiram, .wifislpiram, .wifislprxiram, .wifiextrairam,
  .wifiorslpiram, .coexiram, .iram1). Without them that code lands in
  flash and crashes when called from an interrupt.
- _heap_end ran to the end of SRAM at 0x40880000, over the mask ROM stack
  and ROM data. phy_param_rom sits at 0x4087fce8, inside that range, so a
  growing Go heap would corrupt the PHY. Cap the heap at 0x4087C610.

Also add the espradio build tag to esp32c6.json, matching esp32c3.json
and esp32s3.json.

Signed-off-by: Ron Evans <ron@hybridgroup.com>
2026-08-29 19:30:41 +02:00
14 changed files with 1316 additions and 586 deletions
-35
View File
@@ -1,35 +0,0 @@
#!/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"
-158
View File
@@ -1,158 +0,0 @@
# 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
View File
@@ -123,35 +123,3 @@ 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
View File
@@ -1,163 +1,3 @@
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**
+2 -2
View File
@@ -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 intrinsics and library calls. // memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
// 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.*.
-1
View File
@@ -25,7 +25,6 @@ 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.
+3 -5
View File
@@ -417,7 +417,6 @@ 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() == "_" {
@@ -431,7 +430,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(b.CreateMul(hash, multiplier, ""), fieldHash, "") hash = b.CreateXor(hash, fieldHash, "")
} }
return hash return hash
case *types.Array: case *types.Array:
@@ -446,7 +445,6 @@ 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)
@@ -454,7 +452,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(b.CreateMul(hash, multiplier, ""), elemHash, "") hash = b.CreateXor(hash, elemHash, "")
} }
return hash return hash
} }
@@ -473,7 +471,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(b.CreateMul(phiHash, multiplier, ""), elemHash, "") newHash := b.CreateXor(phiHash, 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)
-20
View File
@@ -12,11 +12,6 @@ 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]
@@ -37,21 +32,6 @@ 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() {
} }
-147
View File
@@ -4,7 +4,6 @@ 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
@@ -98,152 +97,6 @@ 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
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" const version = "0.42.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).
-1
View File
@@ -576,7 +576,6 @@ 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
+2 -1
View File
@@ -6,7 +6,8 @@
"features": "+32bit,+a,+c,+m,+zaamo,+zalrsc,+zmmul,-relax", "features": "+32bit,+a,+c,+m,+zaamo,+zalrsc,+zmmul,-relax",
"build-tags": [ "build-tags": [
"esp32c6", "esp32c6",
"esp" "esp",
"espradio"
], ],
"serial": "usb", "serial": "usb",
"rtlib": "compiler-rt", "rtlib": "compiler-rt",
+1303 -3
View File
File diff suppressed because it is too large Load Diff
-15
View File
@@ -1,15 +0,0 @@
package main
import "reflect"
type value struct {
Field int
}
//go:wasmexport typeNameLength
func typeNameLength() uint32 {
return uint32(len(reflect.TypeOf(value{}).String()))
}
func main() {
}