Files
tinygo/transform/testdata/allocs2.go
Ayke van Laethem df09dbdf0f transform: restore previous test behavior
I think it's much nicer to have the test output inline in the source
file, that way it's much easier to review any changes. For example, when
escape analysis is improved this is visible with removed `// OUT` lines.

This is similar to how LLVM writes its tests, and I like that style.
2026-06-25 23:26:06 +02:00

177 lines
3.3 KiB
Go

package main
import (
"runtime/volatile"
"unsafe"
)
func main() {
n1 := 5
derefInt(&n1)
n2 := 6
returnIntPtr(&n2)
s1 := make([]int, 3)
readIntSlice(s1)
s2 := [3]int{}
readIntSlice(s2[:])
s3 := make([]int, 3)
returnIntSlice(s3)
useSlice(make([]int, getUnknownNumber())) // OUT: size is not constant
s4 := make([]byte, 300) // OUT: object size 300 exceeds maximum stack allocation size 256
readByteSlice(s4)
s5 := make([]int, 4) // OUT: escapes at line 30
_ = append(s5, 5)
s6 := make([]int, 3)
s7 := []int{1, 2, 3}
copySlice(s6, s7)
c1 := getComplex128() // OUT: escapes at line 37
useInterface(c1)
n3 := 5
func() int {
return n3
}()
callVariadic(3, 5, 8) // OUT: escapes at line 44
s8 := []int{3, 5, 8} // OUT: escapes at line 47
callVariadic(s8...)
n4 := 3 // OUT: escapes at line 51
n5 := 7 // OUT: escapes at line 51
func() {
n4 = n5
}()
println(n4, n5)
// This shouldn't escape.
var buf [32]byte
s := string(buf[:])
println(len(s))
var rbuf [5]rune
s = string(rbuf[:])
println(s)
// Unsafe usage of DMA buffers: the compiler thinks this buffer won't be
// used anymore after the volatile store.
var dmaBuf1 [4]byte
pseudoVolatile.Set(uint32(unsafeNoEscape(unsafe.Pointer(&dmaBuf1[0]))))
// Safe usage of DMA buffers: keep the buffer alive until it is no longer
// needed, but don't mark it as needing to be heap allocated. The compiler
// will keep the buffer stack allocated if possible.
var dmaBuf2 [4]byte
pseudoVolatile.Set(uint32(unsafeNoEscape(unsafe.Pointer(&dmaBuf2[0]))))
// ...use the buffer in the DMA peripheral
keepAliveNoEscape(unsafe.Pointer(&dmaBuf2[0]))
}
type vector3 [3]float32
func scaleVector3(vec *vector3, f float32) *vector3 {
vec[0] *= f
vec[1] *= f
vec[2] *= f
return vec
}
func crossVector3(a, b *vector3) vector3 {
return vector3{
a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0],
}
}
func nonEscapingReturnedPointer() vector3 {
a := vector3{1, 2, 3}
b := vector3{4, 5, 6}
c := scaleVector3(&b, 0.5)
return crossVector3(&a, c)
}
var escapedSlice []int
func escapingReturnedSlice() {
s := make([]int, 3) // OUT: escapes at line 108
escapedSlice = returnIntSlice(s)
}
var escapedVector3 *vector3
func escapingReturnedPointer() {
b := vector3{4, 5, 6} // OUT: escapes at line 117
c := scaleVector3(&b, 0.5)
escapedVector3 = c
}
func recursiveScaleVector3(vec *vector3, n int) *vector3 {
if n == 0 {
return vec
}
return recursiveScaleVector3(vec, n-1)
}
func recursiveReturnedPointer() vector3 {
b := vector3{4, 5, 6} // OUT: escapes at unknown line
c := recursiveScaleVector3(&b, 1)
return *c
}
func derefInt(x *int) int {
return *x
}
func returnIntPtr(x *int) *int {
return x
}
func readIntSlice(s []int) int {
return s[1]
}
func readByteSlice(s []byte) byte {
return s[1]
}
func returnIntSlice(s []int) []int {
return s
}
func getUnknownNumber() int
func copySlice(out, in []int) {
copy(out, in)
}
func getComplex128() complex128
func useInterface(interface{})
func callVariadic(...int)
func useSlice([]int)
// See the function with the same name in the machine package.
//
//go:linkname unsafeNoEscape machine.unsafeNoEscape
func unsafeNoEscape(ptr unsafe.Pointer) uintptr
//go:linkname keepAliveNoEscape machine.keepAliveNoEscape
func keepAliveNoEscape(ptr unsafe.Pointer)
var pseudoVolatile volatile.Register32