compiler: add support for the append builtin
Этот коммит содержится в:
родитель
b81aecf753
коммит
963ba16d7b
5 изменённых файлов: 112 добавлений и 11 удалений
|
@ -1654,6 +1654,34 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
|
||||||
|
|
||||||
func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string) (llvm.Value, error) {
|
func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string) (llvm.Value, error) {
|
||||||
switch callName {
|
switch callName {
|
||||||
|
case "append":
|
||||||
|
src, err := c.parseExpr(frame, args[0])
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
elems, err := c.parseExpr(frame, args[1])
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
srcBuf := c.builder.CreateExtractValue(src, 0, "append.srcBuf")
|
||||||
|
srcPtr := c.builder.CreateBitCast(srcBuf, c.i8ptrType, "append.srcPtr")
|
||||||
|
srcLen := c.builder.CreateExtractValue(src, 1, "append.srcLen")
|
||||||
|
srcCap := c.builder.CreateExtractValue(src, 2, "append.srcCap")
|
||||||
|
elemsBuf := c.builder.CreateExtractValue(elems, 0, "append.elemsBuf")
|
||||||
|
elemsPtr := c.builder.CreateBitCast(elemsBuf, c.i8ptrType, "append.srcPtr")
|
||||||
|
elemsLen := c.builder.CreateExtractValue(elems, 1, "append.elemsLen")
|
||||||
|
elemType := srcBuf.Type().ElementType()
|
||||||
|
elemSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(elemType), false)
|
||||||
|
result := c.createRuntimeCall("sliceAppend", []llvm.Value{srcPtr, elemsPtr, srcLen, srcCap, elemsLen, elemSize}, "append.new")
|
||||||
|
newPtr := c.builder.CreateExtractValue(result, 0, "append.newPtr")
|
||||||
|
newBuf := c.builder.CreateBitCast(newPtr, srcBuf.Type(), "append.newBuf")
|
||||||
|
newLen := c.builder.CreateExtractValue(result, 1, "append.newLen")
|
||||||
|
newCap := c.builder.CreateExtractValue(result, 2, "append.newCap")
|
||||||
|
newSlice := llvm.Undef(src.Type())
|
||||||
|
newSlice = c.builder.CreateInsertValue(newSlice, newBuf, 0, "")
|
||||||
|
newSlice = c.builder.CreateInsertValue(newSlice, newLen, 1, "")
|
||||||
|
newSlice = c.builder.CreateInsertValue(newSlice, newCap, 2, "")
|
||||||
|
return newSlice, nil
|
||||||
case "cap":
|
case "cap":
|
||||||
value, err := c.parseExpr(frame, args[0])
|
value, err := c.parseExpr(frame, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -83,17 +83,6 @@ func memequal(x, y unsafe.Pointer, n uintptr) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builtin copy(dst, src) function: copy bytes from dst to src.
|
|
||||||
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen lenType, elemSize uintptr) lenType {
|
|
||||||
// n = min(srcLen, dstLen)
|
|
||||||
n := srcLen
|
|
||||||
if n > dstLen {
|
|
||||||
n = dstLen
|
|
||||||
}
|
|
||||||
memmove(dst, src, uintptr(n)*elemSize)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname sleep time.Sleep
|
//go:linkname sleep time.Sleep
|
||||||
func sleep(d int64) {
|
func sleep(d int64) {
|
||||||
sleepTicks(timeUnit(d / tickMicros))
|
sleepTicks(timeUnit(d / tickMicros))
|
||||||
|
|
53
src/runtime/slice.go
Обычный файл
53
src/runtime/slice.go
Обычный файл
|
@ -0,0 +1,53 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// This file implements compiler builtins for slices: append() and copy().
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builtin append(src, elements...) function: append elements to src and return
|
||||||
|
// the modified (possibly expanded) slice.
|
||||||
|
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen lenType, elemSize uintptr) (unsafe.Pointer, lenType, lenType) {
|
||||||
|
if elemsLen == 0 {
|
||||||
|
// Nothing to append, return the input slice.
|
||||||
|
return srcBuf, srcLen, srcCap
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcLen+elemsLen > srcCap {
|
||||||
|
// Slice does not fit, allocate a new buffer that's large enough.
|
||||||
|
srcCap = srcCap * 2
|
||||||
|
if srcCap == 0 { // e.g. zero slice
|
||||||
|
srcCap = 1
|
||||||
|
}
|
||||||
|
for srcLen+elemsLen > srcCap {
|
||||||
|
// This algorithm may be made more memory-efficient: don't multiply
|
||||||
|
// by two but by 1.5 or something. As far as I can see, that's
|
||||||
|
// allowed by the Go language specification (but may be observed by
|
||||||
|
// programs).
|
||||||
|
srcCap *= 2
|
||||||
|
}
|
||||||
|
buf := alloc(uintptr(srcCap) * elemSize)
|
||||||
|
|
||||||
|
// Copy the old slice to the new slice.
|
||||||
|
if srcLen != 0 {
|
||||||
|
memmove(buf, srcBuf, uintptr(srcLen)*elemSize)
|
||||||
|
}
|
||||||
|
srcBuf = buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// The slice fits (after possibly allocating a new one), append it in-place.
|
||||||
|
memmove(unsafe.Pointer(uintptr(srcBuf)+uintptr(srcLen)*elemSize), elemsBuf, uintptr(elemsLen)*elemSize)
|
||||||
|
return srcBuf, srcLen + elemsLen, srcCap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Builtin copy(dst, src) function: copy bytes from dst to src.
|
||||||
|
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen lenType, elemSize uintptr) lenType {
|
||||||
|
// n = min(srcLen, dstLen)
|
||||||
|
n := srcLen
|
||||||
|
if n > dstLen {
|
||||||
|
n = dstLen
|
||||||
|
}
|
||||||
|
memmove(dst, src, uintptr(n)*elemSize)
|
||||||
|
return n
|
||||||
|
}
|
24
testdata/slice.go
предоставленный
24
testdata/slice.go
предоставленный
|
@ -8,8 +8,32 @@ func main() {
|
||||||
printslice("bar", bar)
|
printslice("bar", bar)
|
||||||
printslice("foo[1:2]", foo[1:2])
|
printslice("foo[1:2]", foo[1:2])
|
||||||
println("sum foo:", sum(foo))
|
println("sum foo:", sum(foo))
|
||||||
|
|
||||||
|
// copy
|
||||||
println("copy foo -> bar:", copy(bar, foo))
|
println("copy foo -> bar:", copy(bar, foo))
|
||||||
printslice("bar", bar)
|
printslice("bar", bar)
|
||||||
|
|
||||||
|
// append
|
||||||
|
var grow []int
|
||||||
|
printslice("grow", grow)
|
||||||
|
grow = append(grow, 42)
|
||||||
|
printslice("grow", grow)
|
||||||
|
grow = append(grow, -1, -2)
|
||||||
|
printslice("grow", grow)
|
||||||
|
grow = append(grow, foo...)
|
||||||
|
printslice("grow", grow)
|
||||||
|
grow = append(grow)
|
||||||
|
printslice("grow", grow)
|
||||||
|
grow = append(grow, grow...)
|
||||||
|
printslice("grow", grow)
|
||||||
|
|
||||||
|
// append string to []bytes
|
||||||
|
bytes := append([]byte{1, 2, 3}, "foo"...)
|
||||||
|
print("bytes: len=", len(bytes), " cap=", cap(bytes), " data:")
|
||||||
|
for _, n := range bytes {
|
||||||
|
print(" ", n)
|
||||||
|
}
|
||||||
|
println()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printslice(name string, s []int) {
|
func printslice(name string, s []int) {
|
||||||
|
|
7
testdata/slice.txt
предоставленный
7
testdata/slice.txt
предоставленный
|
@ -4,3 +4,10 @@ foo[1:2]: len=1 cap=3 data: 2
|
||||||
sum foo: 12
|
sum foo: 12
|
||||||
copy foo -> bar: 3
|
copy foo -> bar: 3
|
||||||
bar: len=3 cap=5 data: 1 2 4
|
bar: len=3 cap=5 data: 1 2 4
|
||||||
|
grow: len=0 cap=0 data:
|
||||||
|
grow: len=1 cap=1 data: 42
|
||||||
|
grow: len=3 cap=4 data: 42 -1 -2
|
||||||
|
grow: len=7 cap=8 data: 42 -1 -2 1 2 4 5
|
||||||
|
grow: len=7 cap=8 data: 42 -1 -2 1 2 4 5
|
||||||
|
grow: len=14 cap=16 data: 42 -1 -2 1 2 4 5 42 -1 -2 1 2 4 5
|
||||||
|
bytes: len=6 cap=6 data: 1 2 3 102 111 111
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче