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.
This commit is contained in:
Nia Waldvogel
2025-12-26 19:19:21 -05:00
committed by Nia
parent bc9708f51a
commit a40586d092
17 changed files with 353 additions and 358 deletions
+7 -4
View File
@@ -1738,6 +1738,9 @@ func (e *ValueError) Error() string {
//go:linkname memcpy runtime.memcpy
func memcpy(dst, src unsafe.Pointer, size uintptr)
//go:linkname memmove runtime.memmove
func memmove(dst, src unsafe.Pointer, size uintptr)
//go:linkname memzero runtime.memzero
func memzero(ptr unsafe.Pointer, size uintptr)
@@ -1747,9 +1750,6 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
//go:linkname sliceAppend runtime.sliceAppend
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr)
//go:linkname sliceCopy runtime.sliceCopy
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int
// Copy copies the contents of src into dst until either
// dst has been filled or src has been exhausted.
func Copy(dst, src Value) int {
@@ -1779,7 +1779,10 @@ func Copy(dst, src Value) int {
dst.checkRO()
}
return sliceCopy(dstbuf, srcbuf, dstlen, srclen, dst.typecode.elem().Size())
minLen := min(dstlen, srclen)
elemSize := dst.typecode.elem().Size()
memmove(dstbuf, srcbuf, minLen*elemSize)
return int(minLen)
}
func buflen(v Value) (unsafe.Pointer, uintptr) {
-11
View File
@@ -23,17 +23,6 @@ func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen, elem
return srcBuf, newLen, srcCap
}
// Builtin copy(dst, src) function: copy bytes from dst to src.
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int {
// n = min(srcLen, dstLen)
n := srcLen
if n > dstLen {
n = dstLen
}
memmove(dst, src, n*elemSize)
return int(n)
}
// sliceGrow returns a new slice with space for at least newCap elements
func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr) {
if oldCap >= newCap {