mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
machine: make sure DMA buffers do not escape unnecessarily
Writing the pointer of a buffer to memory-mapped I/O will normally cause it to escape, which forces the compiler to heap-allocate the buffer. But we do know how long the value stays alive, so we can tell the compiler to keep it alive exactly until it is not needed anymore - and tell it to not treat the pointer-to-uintptr cast as escaping.
This commit is contained in:
committed by
Ron Evans
parent
5ae8fd1f6f
commit
b203314c2f
Vendored
+36
-8
@@ -1,11 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n1 := 5
|
||||
derefInt(&n1)
|
||||
|
||||
// This should eventually be modified to not escape.
|
||||
n2 := 6 // OUT: object allocated on the heap: escapes at line 9
|
||||
n2 := 6 // OUT: object allocated on the heap: escapes at line 14
|
||||
returnIntPtr(&n2)
|
||||
|
||||
s1 := make([]int, 3)
|
||||
@@ -15,7 +20,7 @@ func main() {
|
||||
readIntSlice(s2[:])
|
||||
|
||||
// This should also be modified to not escape.
|
||||
s3 := make([]int, 3) // OUT: object allocated on the heap: escapes at line 19
|
||||
s3 := make([]int, 3) // OUT: object allocated on the heap: escapes at line 24
|
||||
returnIntSlice(s3)
|
||||
|
||||
useSlice(make([]int, getUnknownNumber())) // OUT: object allocated on the heap: size is not constant
|
||||
@@ -23,14 +28,14 @@ func main() {
|
||||
s4 := make([]byte, 300) // OUT: object allocated on the heap: object size 300 exceeds maximum stack allocation size 256
|
||||
readByteSlice(s4)
|
||||
|
||||
s5 := make([]int, 4) // OUT: object allocated on the heap: escapes at line 27
|
||||
s5 := make([]int, 4) // OUT: object allocated on the heap: escapes at line 32
|
||||
_ = append(s5, 5)
|
||||
|
||||
s6 := make([]int, 3)
|
||||
s7 := []int{1, 2, 3}
|
||||
copySlice(s6, s7)
|
||||
|
||||
c1 := getComplex128() // OUT: object allocated on the heap: escapes at line 34
|
||||
c1 := getComplex128() // OUT: object allocated on the heap: escapes at line 39
|
||||
useInterface(c1)
|
||||
|
||||
n3 := 5
|
||||
@@ -38,13 +43,13 @@ func main() {
|
||||
return n3
|
||||
}()
|
||||
|
||||
callVariadic(3, 5, 8) // OUT: object allocated on the heap: escapes at line 41
|
||||
callVariadic(3, 5, 8) // OUT: object allocated on the heap: escapes at line 46
|
||||
|
||||
s8 := []int{3, 5, 8} // OUT: object allocated on the heap: escapes at line 44
|
||||
s8 := []int{3, 5, 8} // OUT: object allocated on the heap: escapes at line 49
|
||||
callVariadic(s8...)
|
||||
|
||||
n4 := 3 // OUT: object allocated on the heap: escapes at line 48
|
||||
n5 := 7 // OUT: object allocated on the heap: escapes at line 48
|
||||
n4 := 3 // OUT: object allocated on the heap: escapes at line 53
|
||||
n5 := 7 // OUT: object allocated on the heap: escapes at line 53
|
||||
func() {
|
||||
n4 = n5
|
||||
}()
|
||||
@@ -58,6 +63,19 @@ func main() {
|
||||
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]))
|
||||
}
|
||||
|
||||
func derefInt(x *int) int {
|
||||
@@ -93,3 +111,13 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user