57 Commits

Author SHA1 Message Date
Jake Bailey 16fc1ea2bb runtime: make fatal failures unrecoverable
Match the Go runtime by terminating for deadlocks, stack overflows,
runtime and GC invariants, invalid lock operations, and platform
initialization failures instead of routing them through panic/recover.

Keep language-level runtime errors and unsupported user operations
recoverable. Add crash coverage that verifies fatal errors bypass deferred
recover calls.
2026-07-25 07:14:00 +02:00
deadprogram 0ffa3eb748 all: add LLVM 22 support
Builder:
- Update clang.cpp for LLVM 22 API changes: DiagnosticOptions is no
  longer ref-counted, TextDiagnosticPrinter and DiagnosticsEngine take
  references instead of pointers, createDiagnostics() signature changed.
- Update cc1as.cpp: clang/Driver/Options.h moved to
  clang/Options/Options.h, namespace changed from clang::driver::options
  to clang::options, MCInstPrinter now passed as unique_ptr.
- Add new LLVM 22 libraries to GNUmakefile: clangAnalysisLifetimeSafety,
  clangOptions, LLVMDTLTO, and dtlto component.
- Add llvm22 build tag to all build/test commands.

CGo:
- Handle CXType_Unexposed in libclang.go by resolving via canonical
  type. LLVM 22 reports builtin type aliases (e.g. __size_t) as
  Unexposed instead of Typedef.
- Always make C typedefs into Go type aliases. LLVM 22 changed
  getTypedefDeclUnderlyingType to return CXType_Enum directly instead
  of wrapping in an elaborated type.

Compileopts:
- Add build-tag-guarded ClangTriple() to substitute wasm32-unknown-wasi
  with wasm32-unknown-wasip1 for LLVM 22 (deprecated triple).
- Add build-tag-guarded patchFeatures() to map renamed Xtensa features
  (atomctl, memctl, timerint, esp32s3) for LLVM 22.

Targets:
- Remove -zca from RISC-V target feature strings (esp32c3, esp32c6,
  fe310, k210, riscv-qemu, tkey). LLVM 22 now implies +zca from +c.
- Remove -zcd from k210. LLVM 22 now implies +zcd from +c,+d.

Tests:
- Change TestClangAttributes to check individual feature flags instead
  of exact string match, allowing new LLVM features without failures.
- Update TestBinarySize expected values for LLVM 22 codegen.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-07-17 19:06:57 +02:00
deadprogram 919c998355 builder: update max supported Go version to 1.27
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-07-14 11:52:59 +02:00
Konstantin Sharlaimov c1a4ed1489 machine/stm32: add OTG FS USB driver for F4/F7
STM32F4 and F7 share the same OTG FS IP but have no USB driver in
TinyGo. This adds a full device-mode driver covering CDC, HID, and
MSC with working examples.

- OTG FS has 4 physical EPs (0–3); virtual indices 4–7 fold onto
  them via physEP() so the existing machine/usb API is unchanged
- F4 bypasses VBUS sensing via GCCFG.NOVBUSSENS; F7 uses the USB
  voltage regulator + GOTGCTL B-valid override instead
- STM32F7 PLL_Q changed 2→9 to produce the 48 MHz clock required
  by USB/RNG/SDMMC; CK48MSEL cleared to select main PLL as source
- HID and MSC descriptors remapped at init() to physical endpoint
  addresses (EP2/EP1 for HID, EP2/EP3 for MSC)
- usb-storage example replaced machine.Flash with a FAT12 RAM disk
  so the host mounts without reformatting
- MSC sendCSW sets queuedBytes before state transition to fix a
  missed byte-count on the status phase
2026-07-12 10:45:49 +02:00
Jake Bailey e039ce131c runtime: encode pending Goexit in panic state
Treat panicState as a bitmask so a recovered panic during Goexit
can clear the panic bit while preserving the pending Goexit bit.
This removes the separate deferFrame Goexit field and restores the
previous defer frame size.
2026-07-11 11:53:33 +02:00
Jake Bailey 432ebe13ed runtime: make Goexit exit host threads
The threads scheduler handled runtime.Goexit using the generic deadlock
path, which parked the current pthread forever. Add a scheduler-specific
goexit hook so it can remove the current task and exit the pthread while
ordinary blocking deadlocks still block.

Track main goroutine Goexit so the last remaining goroutine reports the
expected deadlock instead of letting the process exit successfully.
Expand the crash coverage with the Goexit cases covered by Big Go's
runtime tests.
2026-07-11 11:53:33 +02:00
Jake Bailey 7c3dc05117 all: modernize (#5498)
* modernize string cut usage

* modernize string cut prefix usage

* modernize slices helper usage

* modernize min and max usage

* modernize loop variable copies

* modernize integer range loops

* modernize map copy loops

* modernize go types iterator usage

* modernize empty interface usage

* modernize atomic type usage

* modernize string builders

* modernize string split iteration

* modernize remaining loop variable copies

* modernize usb cdc min usage

* modernize src integer range loops

* modernize example empty interface usage

* modernize src min and max usage

* modernize src integer range loops

* modernize src empty interface usage

* modernize src atomic type usage

* modernize reflect type lookups

* modernize review nits
2026-07-06 21:58:48 +02:00
Ayke van Laethem 134de98ba5 compiler, runtime: optimize zero-sized allocations
Instead of referring to an unused global, use a constant value. This is
safe even when using `-gc=none` (since no actual memory gets allocated)
which wasn't the case before. It should also reduce binary size by a few
bytes for most programs.
2026-06-25 21:09:43 +02:00
Nia Waldvogel 11c2b76e29 runtime (gc.blocks): move objHeader to the end
This moves the objHeader from before an object body to after it.
On 32-bit systems with 16-byte alignment requirements (x86, ARM, RISC-V), we previously padded the header to a whole block.
This wastes up to 12 bytes, as on -gc=conservative the header is a single pointer.
With this change, no padding is required (beyond that from rounding the size up).

The "head" block in the metadata was moved to the end of the range to match the header location.
This changed the block loop directions throughout the GC logic.
The bit hacks used by sweep no longer work because there is no equivalent of addition that carries downwards.
However it is now possible to merge the sweep and free range list rebuild passes because their loop directions match.

There are two other places where we rebuilt the free ranges list: when initializing or growing the heap.
The former can be easily replaced with a single hardcoded range containing the entire heap.
In the latter case, I opted to only add the new space to the existing list.
These replacements allowed me to fully remove the buildFreeRanges function.
2026-06-16 13:37:35 -04:00
Konstantin Sharlaimov c33113ab5f fix(usb): implement endpoint stall for nRF52840.
Implement SetStallEPIn, SetStallEPOut, ClearStallEPIn, and ClearStallEPOut methods on the nRF52840 USBDevice struct using the hardware EPSTALL register to support MSC driver requirements. Also, correct the handleUSBIRQ loops to iterate over physical endpoint numbers rather than dynamic configuration entries to prevent missed or incorrectly routed endpoint interrupts.
2026-06-12 18:17:25 +02:00
Konstantin Sharlaimov c3f1832d9a refactor(usb): dynamic endpoint descriptor generation
Replace static endpoint variables with EndpointIN and EndpointOUT
functions. Allows flexible endpoint remapping across USB configs.

Map CDC, HID, MIDI and MSC USB devices to bidirectional endpoints consistently across different configurations.
2026-06-12 18:17:25 +02:00
あーるどん d9d19e812e usb/cdc: fix RP2 USB CDC TX race with cores scheduler (#5391)
* usb/cdc: serialize TX pump across cores

* usb/cdc: apply review suggestion

* Clarify TX pump loop comment

* clarify txActive comments

* usb/cdc: document txActive ownership and lost-wakeup recheck

* builder: update wioterminal size expectation

---------

Co-authored-by: rdon <you@example.com>
2026-06-08 13:58:19 +02:00
sago35 ca584de84a machine/usb: support bidirectional endpoints by dynamic registration (#5447)
* machine/usb: support bidirectional endpoints by dynamic registration
2026-06-07 20:33:18 +02:00
sago35 aef70a5839 machine/usb: fix truncated USB string descriptor when host requests short maxLen (#5449)
* machine/usb: fix truncated USB string descriptor when host requests short maxLen
* fix binary size
2026-06-07 13:32:52 +02:00
Konstantin Sharlaimov 8e36d2758b runtime: improve hardfault handler and stack reporting on Cortex-M
- Add reference to the current goroutine stack (PSP) when showing the hardfault info on Cortex-M.
2026-06-05 21:05:36 +02:00
Jake Bailey 278aa09819 compiler: share recoverable fault blocks 2026-06-04 19:25:47 +02:00
Jake Bailey eed4afda63 compiler, runtime: make runtime panics recoverable
Emit fault checkpoints around compiler-generated runtime assertions so
runtimePanicAt can unwind through the existing defer/recover machinery
instead of aborting. This lets panics from bounds checks, type checks,
and other compiler-inserted runtime checks be recovered by deferred
functions.

Mark functions that call recover as noinline. Inlining such a function
into a deferred closure can make recover observe the wrong call context
and report success when it should return nil.

Addresses tinygo-org/tinygo issues 2759 and 3510.
2026-06-04 19:25:47 +02:00
deadprogram d2f60c02bb fix: correctly handle interrupt disable on esp32-c3
Priority 0 disables an interrupt on ESP32-C3. This corrects
the code to actually use that.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-04-05 14:15:40 +02:00
Pat Whittingslow 86cc3b6c12 usb/cdc: Better ring buffer implementation (#5209)
* begin adding ring512 implementation

* refactor to make operation driven fuzz test

* refactor USBCDC.Read to use ring512

* try txhandler separate to flush

* working USBCDC with large packets

* fix binary size

* remove comment

* documentation improvements
2026-04-05 14:15:40 +02:00
Nia Waldvogel a40586d092 compiler: implement copy directly
The compiler now implements the copy builtin directly instead of calling sliceCopy.
The length is calculated with the llvm.umax.* intrinsics, and the move is performed by llvm.memmove.*.
Both of these operations are easily understood by LLVM's optimization passes.
The type's alignment is also provided to llvm.memmove.*, which is useful when rewriting the move.

Interp no longer needs to reimplement sliceCopy.
Some edge case handling was implemented by sliceCopy but not llvm.memmove.*/llvm.memcpy.*.
I copied this over, so copies of external slices should work now.
Volatile moves/copies are now run at runtime by interp.

There is a 4-byte size increase due to some confusing length logic in sendUSBPacket.
I will look at sendUSBPacket in a future PR.
2026-01-05 15:10:31 -05:00
Nia Waldvogel 8ef36ed939 machine: fix usb truncation?
Remove the sendUSBPacket maxLen param because this greatly confused the compiler.
It also fixes a bug where the length provided to the hardware may not match the length of the packet.
sendUSBPacket now panics if the sent packet is too big.

I also fixed some of the string descriptor logic where we could create a packet without fully populating it.

RP2* systems might require some more work since they are implemented very differently?
I don't have any of those to test with yet, so maybe someone can deal with them in a seperate PR?
2026-01-03 10:59:50 +00:00
Nia Waldvogel d01d0bb358 runtime (gc_blocks.go): make sweep branchless
Instead of looping over each block, we can use bit hacks to operate on an entire state byte.
I deinterleaved the state bits in order to enable these tricks.

Sweep used to count free/freed allocations/blocks.
I managed to move/remove all of these counters:
- The free space is now calculated in buildFreeRanges by adding the range lengths.
- ReadMemStats counts freed objects by subtracting live objects from allocated objects.
- gcFreedBlocks was never necessary because MemStats.HeapAlloc is the same as MemStats.HeapInUse.
2025-12-10 18:39:50 -05:00
Nia Waldvogel 8fcf3658b1 runtime (gc_blocks.go): use best-fit allocation
The allocator originally just looped through the blocks until it found a sufficiently-long range.
This is simple, but it fragments very easily and can degrade to a full heap scan for long requests.

Instead, we now maintain a sorted nested list of free ranges by size.
The allocator will select the shortest sufficient-length range, generally reducing fragmentation.
This data structure can find a range in time directly proportional to the requested length.
2025-12-10 06:58:07 +00:00
Nia Waldvogel 26ac03a3f6 runtime (gc_blocks.go): simplify scanning logic
Loop over valid pointer locations in heap objects instead of checking if each location is valid.
The conservative scanning code is now shared between markRoots and the heap scan.

This also removes the ending alignment requirement from markRoots, since the new scan* functions do not require an aligned length.
This requirement was occasionally violated by the linux global marking code.

This saves some code space and has negligible impact on performance.
2025-12-05 10:16:38 +00:00
Nia Waldvogel c9aa88b8ef runtime (gc_blocks.go): use a linked stack to scan marked objects
The blocks GC originally used a fixed-size stack to hold objects to scan.
When this stack overflowed, the GC would fully rescan all marked objects.
This could cause the GC to degrade to O(n^2) when scanning large linked data structures.

Instead of using a fixed-size stack, we now add a pointer field to the start of each object.
This pointer field is used to implement an unbounded linked stack.
This also consolidates the heap object scanning into one place, which simplifies the process.

This comes at the cost of introducing a pointer field to the start of the object, plus the cost of aligning the result.
This translates to:
- 16 bytes of overhead on x86/arm64 with the conservative collector
- 0 bytes of overhead on x86/arm64 with the precise collector (the layout field cost gets aligned up to 16 bytes anyway)
- 8 bytes of overhead on other 64-bit systems
- 4 bytes of overhead on 32-bit systems
- 2 bytes of overhead on AVR
2025-12-05 10:16:38 +00:00
Nia Waldvogel 20e22d4507 runtime (gc_blocks.go): clear full size of allocation
This fixes a bug where runtime.alloc would not clear the padding from rounding the allocation up to a multiple of the block size.
The GC still has to scan this, and this could result in permanent false positives (and therefore memory leaks).

It also handles overflow in the size calculation.
2025-11-30 08:46:20 +00:00
Ayke van Laethem 8872d5ebfc runtime: fix sleep duration for long sleeps
Long sleep durations weren't implemented correctly, by simply casting to
a smaller number of bits. What we want is a saturating downcast, which
is what I've used here instead.

This should fix https://github.com/tinygo-org/tinygo/issues/3356.
2025-10-16 17:20:50 +02:00
Ayke van Laethem 0a87846bd8 cortexm: optimize code size for the HardFault_Handler
This function is called when a hard fault occurs. Hard faults happen
when something really bad happens - like writing to unwritable memory or
an unaligned memory access on Cortex-M0. It is not generally possible to
recover from these.

This commit optimizes the code size overhead of hard fault handling:

  * It removes the stack overflow checking code.
    This may seem like a bad thing, but the only thing this could check
    were stack overflows outside goroutines. In practice, this could
    only really happen on a stack overflow in the scheduler (unlikely),
    or in interrupt code (possible, but interrupts are small so still
    unlikely). Most stack overflows happen in regular goroutines, and
    weren't caught in the HardFault.
  * It makes the panic message similar to a regular panic. This has two
    advantages:
      * It reduces code size, because the string can be reused between
        the HardFault handler and the runtime panic function.
      * Using the same pattern automatically makes `-monitor` print the
        source address for the hard fault. Not a big benefit as we could
        trivially add any other pattern but a nice benefit nonetheless.

Result:

    $ tinygo flash -target=microbit -size=short -programmer=openocd -monitor examples/serial
       code    data     bss |   flash     ram
       3036       8    2256 |    3044    2264
    [...snip]
    Connected to /dev/ttyACM0. Press Ctrl-C to exit.
    panic: runtime error at 0x00000344: HardFault with sp=0x200007d0
    [tinygo: panic at /home/ayke/src/tinygo/tinygo/src/internal/task/task_stack_cortexm.go:48:4]

(This is with https://github.com/tinygo-org/tinygo/pull/3680 not yet
fixed and some local changes to configure the UART so I can actually see
the panic).

For atsamd21/nrf51 chips this results in a binary size reduction of
around 100 bytes. For other Cortex-M chips it's around 24 bytes but I
hope to change this in the future because a lot of the fault decoding in
runtime_cortexm_hardfault_debug.go should IMHO be done by the TinyGo
monitor instead (I estimate that this would save around 800 bytes on
these chips).
2025-10-03 13:20:18 +02:00
Ayke van Laethem dfbb133ea6 all: add full LLVM 20 support
This switches the Espressif fork from LLVM 19 to LLVM 20, so we can use
the improvements made between those LLVM versions. It also better aligns
with the system-LLVM build method, which currently also defaults to LLVM
20.

Note that this disables the machine outliner for RISC-V. It appears
there's a bug in there somewhere, with the machine outliner enabled the
crypto/elliptic package tests fail with -target=riscv-qemu.
This should ideally be investigated and reported upstream.
2025-09-17 05:28:06 -04:00
Elias Naur 78914382c3 runtime: ensure time.Sleep(d) sleeps at least d
Account for the sleep queue base time in the computation of the wakeup
time.

Tested with the following program on pico2.

  func main() {
  	go func() {
  		for i := range 60 {
  			const delay = 20 * time.Millisecond
  			before := time.Now()
  			time.Sleep(delay)
  			if d := time.Since(before); true || d < delay {
  				log.Println(i, "actual", d, "delay", delay)
  			}
  		}
  	}()
  	time.Sleep(500 * time.Millisecond)
  	log.Println("******** done sleeping ********")
  	select {}
  }

Without this change, the program would print lines such as:

  17 actual 15.494ms delay 20ms
  18 actual 15.49ms delay 20ms
  19 actual 15.585ms delay 20ms
  20 actual 15.493ms delay 20ms
  21 actual 15.494ms delay 20ms
  22 actual 15.487ms delay 20ms
  23 actual 15.498ms delay 20ms
  ******** done sleeping ********
  24 actual 15.548ms delay 20ms
  25 actual 20.011ms delay 20ms
  26 actual 20.01ms delay 20ms
  27 actual 20.011ms delay 20ms
  28 actual 20.015ms delay 20ms

Note that while more than one sleeping goroutine is in the timer queue,
the sleep duration is 5ms short.
2025-08-08 01:32:42 +02:00
Ayke van Laethem 60f8a62978 all: add support for multicore scheduler
This commit adds support for a scheduler that runs a scheduler on all
available cores. It is meant to be used on baremetal systems with a
fixed number of cores, such as the RP2040.

The initial implementation adds support for multicore scheduling to the
riscv-qemu target as a convenient testing target. This means that this
new multicore scheduler is tested in CI, including a bunch of standard
library tests (`make tinygo-test-baremetal`). This should ensure the new
scheduler is reasonably well tested before trying to use it on
harder-to-debug targets like the RP2040.
2025-06-12 21:04:36 +02:00
Ayke van Laethem 0c7c2926f9 runtime: refactor obtaining the system stack
The system stack is only needed when we're not on it. So we can directly
call task.SystemStack() without problems.

This also saves a tiny bit of binary size.
2025-06-12 21:04:36 +02:00
Elias Naur 0f06f59c6e device/arm: clear pending interrupts before enabling them
Without this change, a pending interrupt would spuriously trigger
immediately after enabling. This happens if an interrupt is triggered
during flashing (e.g. by DMA), which survives the subsequent reset.

This behaviour matches e.g. `machine.irqSet` in machine_rp2_rp2350.go.

See 7f970a45, whose symptoms were likely caused by spurious interrupts.
2025-04-16 09:43:23 +02:00
Ayke van Laethem 38e3d55e64 all: add Go 1.24 support 2025-02-25 14:41:42 +01:00
Ayke van Laethem f4fd79f7be runtime: manually initialize xorshift state
This ensures:

 1. The xorshift state is initialized during interp.
 2. The xorshift state gets initialized to a real random number on
    hardware that supports it at runtime.

This fixes a big binary size regression from the previous commit. It's
still not perfect: most programs increase binary size by a few bytes.
But it's not nearly as bad as before.
2025-02-21 11:36:17 +01:00
Ayke van Laethem 9e9768b51d all: add support for LLVM 19 2025-01-20 06:15:33 +01:00
Yurii Soldak 29d2719bad example: naive debouncing for pininterrupt example (#2233) 2025-01-13 13:21:23 -03:00
Ayke van Laethem ee6fcd76f4 builder: add testing for -size=full
This helps to make sure this feature continues to work and we won't
accidentally introduce regressions.
2024-11-26 12:41:12 +01:00
Ayke van Laethem ecc6d16f22 interp: align created globals
Use the alignment from the align attribute of the runtime.alloc call.
This is going to be a more accurate alignment, and is typically smaller
than the default.
2024-11-21 10:19:19 +01:00
Ayke van Laethem 860697257b runtime: optimize findHead
This is similar to https://github.com/tinygo-org/tinygo/pull/3899, but
smaller and hopefully just as efficient.

Thanks to @HattoriHanzo031 for starting this work, benchmarking, and for
improving the performance of the code even further.
2024-11-14 09:28:25 +01:00
Ayke van Laethem a6c4287b4d runtime: don't call sleepTicks with a negative duration
There are rare cases where this can happen, see for example
https://github.com/tinygo-org/tinygo/issues/4568
2024-11-07 15:37:18 +01:00
Damian Gryski 9a6397b325 runtime: bump markStackSize
Every time we overflow the stack, we have to do a full rescan of the heap.  Making this larger
means fewer overflows and thus fewer secondary+ heap scans.
2024-10-25 16:24:01 +02:00
Damian Gryski 158be02ef7 builder: fix sizes 2024-10-07 19:23:49 -07:00
Damian Gryski f3dfe1d49e runtime: seed fastrand() with hardware randomness 2024-10-02 12:40:07 +02:00
Ayke van Laethem 81ce7fb738 LLVM 18 support 2024-05-24 19:12:26 +02:00
Ayke van Laethem 6984af43a0 all: statically link to LLVM 17 instead of LLVM 16
We can now finally do it, now that Espressif has updated their fork.
2024-01-05 21:13:30 +01:00
Ayke van Laethem 3b1913ac57 all: use the new LLVM pass manager
The old LLVM pass manager is deprecated and should not be used anymore.
Moreover, the pass manager builder (which we used to set up a pass
pipeline) is actually removed from LLVM entirely in LLVM 17:
https://reviews.llvm.org/D145387
https://reviews.llvm.org/D145835

The new pass manager does change the binary size in many cases: both
growing and shrinking it. However, on average the binary size remains
more or less the same.

This is needed as a preparation for LLVM 17.
2023-10-04 13:05:58 +02:00
Ayke van Laethem 1d7543e2bf all: switch to LLVM 16
This commit adds support for LLVM 16 and switches to it by default. That
means three LLVM versions are supported at the same time: LLVM 14, 15,
and 16.

This commit includes work by QuLogic:

  * Part of this work was based on a PR by QuLogic:
    https://github.com/tinygo-org/tinygo/pull/3649
    But I also had parts of this already implemented in an old branch I
    already made for LLVM 16.
  * QuLogic also provided a CGo fix here, which is also incorporated in
    this commit:
    https://github.com/tinygo-org/tinygo/pull/3869

The difference with the original PR by QuLogic is that this commit is
more complete:
  * It switches to LLVM 16 by default.
  * It updates some things to also make it work with a self-built LLVM.
  * It fixes the CGo bug in a slightly different way, and also fixes
    another one not included in the original PR.
  * It does not keep compiler tests passing on older LLVM versions. I
    have found this to be quite burdensome and therefore don't generally
    do this - the smoke tests should hopefully catch most regressions.
2023-09-18 21:58:02 +02:00
sago35 3ad2530ee7 atsamd21, atsamd51: add support for USB INTERRUPT OUT 2023-09-16 09:30:05 +02:00
Yurii Soldak cec237917f example: simplify pininterrupt 2023-06-18 10:59:23 +02:00