This fixes the builder for ESP32 (original) by separating the RAM segments loadable by the
ROM bootloader from flash-mapped segments (DROM/IROM) which require MMU setup by startup code.
These changes are needed for to allow for ESP32 to correctly flashing large programs which
as a result require XIP support.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Clang on i386 mingw emits calls to _alloca (decorated as __alloca)
for stack probing. This was provided by chkstk2.S, not chkstk.S
which only provides __chkstk_ms.
Signed-off-by: deadprogram <ron@hybridgroup.com>
cc1as: change AssemblerInvocation.Triple from std::string to
llvm::Triple, matching upstream LLVM 22 and fixing deprecation warnings
for lookupTarget, createMCRegInfo, createMCAsmInfo, and
createMCSubtargetInfo.
interp: always use ConstNamedStruct in rawValue.toLLVMValue instead of
falling back to ConstStruct for unnamed structs. LLVM 22 uses anonymous
identified struct types where previous versions used literal structs;
ConstStruct creates a literal type that doesn't match, causing an
"initializer type mismatch" panic for globals like fmt.ppFree.
compileopts: add build-tag-guarded feature patching for pre-LLVM 20
(strip +bulk-memory-opt and +call-indirect-overlong from wasm features)
and restructure into three files covering all LLVM version ranges.
targets: strip redundant negative features from RISC-V target JSONs
(esp32c3, esp32c6, fe310, k210, riscv-qemu, tkey). These ~190 negative
features per target listed every extension LLVM knows about that the
target doesn't use, but LLVM disables them by default. They became stale
across LLVM versions, causing "not a recognized feature" warnings. Keep
only positive features and -relax.
Signed-off-by: deadprogram <ron@hybridgroup.com>
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>
Go 1.27 packages can emit stack probes on Windows amd64 and arm64.
Link the compiler-rt stack probe builtins and use compiler-rt for those
targets so these packages build.
Go 1.27 adds generic methods (golang/go#77273). golang.org/x/tools
go/ssa v0.42.0 does not instantiate them: objectMethod only applies
receiverTypeArgs and ignores method-level type parameters, so a call
such as (*math/rand/v2.Rand).N resolves to the abstract generic method
and its body reaches createConst with a type-parameter-typed zero
constant, triggering "panic: expected nil interface constant".
Upgrade golang.org/x/tools to v0.47.0, whose go/ssa returns nil from
MethodValue for generic methods and instantiates method-level type
parameters. No compiler changes are required.
Since x/tools v0.47.0 requires Go 1.25, raise the minimum supported Go
version from 1.24 to 1.25.
Signed-off-by: deadprogram <ron@hybridgroup.com>
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
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.
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.
* Add LinkerFlavor so the odd pairing of COFF+Linux is possible (necessary for UEFI)
* But back bits of builder.go that were mistakenly removed
* Update compileopts/config.go
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
* update LinkerFlavor test
---------
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
A SHT_NOBITS section was unconditionally treated as .bss (RAM) unless it
was the stack. The ESP linker scripts emit non-writable SHT_NOBITS
sections (.irom_dummy / .rodata_dummy) that merely reserve the
flash-mapped XIP virtual address ranges and occupy no RAM. Counting them
inflated the reported bss/RAM usage.
Signed-off-by: deadprogram <ron@hybridgroup.com>
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.
This adds a minimal esp32c6 implementation, currently only
supporting the examples/serial and examples/blinky1 programs.
It does correctly output the expected "Hello, World" via the
serial port, as well as blink the onboard LED.
In addition, it adds support for the PLIC based IRQ handling
as used on the ESP32C6 processor.
Some parts of this code are loosely based on PR #5252 and #5248
Signed-off-by: deadprogram <ron@hybridgroup.com>
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.
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.
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.
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.
This has the following effects:
* It fixes issue #5414.
* It bumps the minimum Go version to Go 1.24 (from 1.23).
I looked, and there doesn't seem to be a version of golang.org/x/tools
that supports the improved `new` builtin without also bumping the
minimum Go version.
* interp: bail out of loops that iterate too many times
The existing loop guard (errLoopUnrolled) only fires when a loop body
emits runtime instructions. Loops that are fully evaluable at compile
time, such as inserting thousands of entries into a map, were not
caught and could hang the compiler.
Add a per-basic-block iteration counter that triggers a recoverable
error (errLoopTooLong) when any block is entered more than 1000 times
in a single function call. This defers the init function to runtime,
which is the same behavior as other interp bailouts.
Profiling showed that 83% of CPU time was spent in GC, caused by
allocation pressure from the interp memory cloning on each map
mutation. The iteration limit avoids this entirely by bailing out
before the quadratic cost becomes significant.
Performance on the reproducer from #2090 (map init with strconv.Itoa):
entries before after
5,000 7.4s 2.1s
10,000 17.5s 2.1s
20,000 48.0s 2.8s
65,536 >180s (OOM) 3.2s
* Add -interp-loop-limit
Several places used the (*[1 << N]T)(ptr)[:len:len] pattern to convert
C pointers to Go slices. This has a hardcoded size limit that can panic
if exceeded; RunTool hit this with >1024 linker arguments when many
files are embedded.
Replace all instances with unsafe.Slice, which handles any size.
When a string variable already had a source-level default value, the -ldflags
"-X" flag was silently ignored and the variable remained the default value
at runtime.
Fix by stripping the InitOrder entry for each -X variable before
LoadSSA() is called. With no entry in InitOrder, go/ssa emits no init
store, so the global stays zero-valued in the IR. makeGlobalsModule
still injects the actual -X values at final link time.
The -X values remain out of the per-package build cache with only the
variable names appearing in the cache key.
Signed-off-by: deadprogram <ron@hybridgroup.com>
The -march flag for compiling C libraries (compiler-rt, picolibc) was
hardcoded to rv32imac for all riscv32 targets. This is incorrect for
targets that lack the atomic extension, such as ESP32-C3 (rv32imc) and
TKey (rv32iczmmul).
Extract the -march value from the target's cflags when available,
falling back to the previous defaults (rv32imac, rv64gc) for targets
that don't override it.
Fixes#5114
Signed-off-by: deadprogram <ron@hybridgroup.com>
The previous approach of erasing basic blocks one-by-one from
duplicate function definitions could crash with a segfault. When
a function has complex control flow (branches, switches, PHI nodes),
deleting a basic block that is still referenced by instructions in
other blocks of the same function causes use-after-free in LLVM.
LLVM's C++ Function::deleteBody() avoids this by calling
dropAllReferences() on all blocks first, but that API is not
exposed in the Go LLVM bindings.
Fix this by using a completely different approach: instead of
manually deleting the function body, set the duplicate function's
linkage to LinkOnceODRLinkage. This tells the LLVM linker that the
definition can be merged with another copy, causing it to prefer
the already-linked ExternalLinkage definition in the destination
module. The result is the same (the runtime's definition wins) but
without any unsafe block manipulation.
Go 1.26 changed syscall.loadlibrary, syscall.loadsystemlibrary, and
syscall.getprocaddress from declarations to definitions in
syscall/dll_windows.go. TinyGo's runtime also defines these via
//go:linkname, causing "symbol multiply defined!" during LLVM module
linking.
Resolve this by detecting duplicate function definitions before calling
llvm.LinkModules and turning the incoming duplicate into a declaration,
so the runtime's version wins. TinyGo's implementations must take
precedence because Go 1.26's versions depend on //go:cgo_import_dynamic,
which TinyGo does not support.
Also fix the signature of syscall_loadsystemlibrary to match the
standard library (remove unused absoluteFilepath parameter).
Signed-off-by: deadprogram <ron@hybridgroup.com>
This fixes an "index out of range" panic that occurs when calculating
binary sizes. The strings.SplitN operation in findPackagePath can sometimes
return a slice with only one element, so we now verify the length of the
slice before attempting to access the second element.
Signed-off-by: deadprogram <ron@hybridgroup.com>
* 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
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.
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?
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.
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.
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.
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
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.