compiler: implement clear builtin for maps
Этот коммит содержится в:
родитель
a2f886a67a
коммит
f1e25a18d2
7 изменённых файлов: 64 добавлений и 0 удалений
|
@ -1631,6 +1631,10 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||||
}, "")
|
}, "")
|
||||||
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
|
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
|
||||||
|
|
||||||
|
return llvm.Value{}, nil
|
||||||
|
case *types.Map:
|
||||||
|
m := argValues[0]
|
||||||
|
b.createMapClear(m)
|
||||||
return llvm.Value{}, nil
|
return llvm.Value{}, nil
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
|
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
|
||||||
|
|
|
@ -185,6 +185,11 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the given map.
|
||||||
|
func (b *builder) createMapClear(m llvm.Value) {
|
||||||
|
b.createRuntimeCall("hashmapClear", []llvm.Value{m}, "")
|
||||||
|
}
|
||||||
|
|
||||||
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
||||||
// map. It returns a tuple of {bool, key, value} with the result of the
|
// map. It returns a tuple of {bool, key, value} with the result of the
|
||||||
// iteration.
|
// iteration.
|
||||||
|
|
4
compiler/testdata/go1.21.go
предоставленный
4
compiler/testdata/go1.21.go
предоставленный
|
@ -59,3 +59,7 @@ func clearSlice(s []int) {
|
||||||
func clearZeroSizedSlice(s []struct{}) {
|
func clearZeroSizedSlice(s []struct{}) {
|
||||||
clear(s)
|
clear(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearMap(m map[string]int) {
|
||||||
|
clear(m)
|
||||||
|
}
|
||||||
|
|
9
compiler/testdata/go1.21.ll
предоставленный
9
compiler/testdata/go1.21.ll
предоставленный
|
@ -147,6 +147,15 @@ entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||||
|
|
||||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
declare i32 @llvm.smin.i32(i32, i32) #4
|
declare i32 @llvm.smin.i32(i32, i32) #4
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,35 @@ func hashmapMakeUnsafePointer(keySize, valueSize uintptr, sizeHint uintptr, alg
|
||||||
return (unsafe.Pointer)(hashmapMake(keySize, valueSize, sizeHint, alg))
|
return (unsafe.Pointer)(hashmapMake(keySize, valueSize, sizeHint, alg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all entries from the map, without actually deallocating the space for
|
||||||
|
// it. This is used for the clear builtin, and can be used to reuse a map (to
|
||||||
|
// avoid extra heap allocations).
|
||||||
|
func hashmapClear(m *hashmap) {
|
||||||
|
if m == nil {
|
||||||
|
// Nothing to do. According to the spec:
|
||||||
|
// > If the map or slice is nil, clear is a no-op.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.count = 0
|
||||||
|
numBuckets := uintptr(1) << m.bucketBits
|
||||||
|
bucketSize := hashmapBucketSize(m)
|
||||||
|
for i := uintptr(0); i < numBuckets; i++ {
|
||||||
|
bucket := hashmapBucketAddr(m, m.buckets, i)
|
||||||
|
for bucket != nil {
|
||||||
|
// Clear the tophash, to mark these keys/values as removed.
|
||||||
|
bucket.tophash = [8]uint8{}
|
||||||
|
|
||||||
|
// Clear the keys and values in the bucket so that the GC won't pin
|
||||||
|
// these allocations.
|
||||||
|
memzero(unsafe.Add(unsafe.Pointer(bucket), unsafe.Sizeof(hashmapBucket{})), bucketSize-unsafe.Sizeof(hashmapBucket{}))
|
||||||
|
|
||||||
|
// Move on to the next bucket in the chain.
|
||||||
|
bucket = bucket.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func hashmapKeyEqualAlg(alg hashmapAlgorithm) func(x, y unsafe.Pointer, n uintptr) bool {
|
func hashmapKeyEqualAlg(alg hashmapAlgorithm) func(x, y unsafe.Pointer, n uintptr) bool {
|
||||||
switch alg {
|
switch alg {
|
||||||
case hashmapAlgorithmBinary:
|
case hashmapAlgorithmBinary:
|
||||||
|
|
11
testdata/go1.21.go
предоставленный
11
testdata/go1.21.go
предоставленный
|
@ -15,4 +15,15 @@ func main() {
|
||||||
s := []int{1, 2, 3, 4, 5}
|
s := []int{1, 2, 3, 4, 5}
|
||||||
clear(s[:3])
|
clear(s[:3])
|
||||||
println("cleared s[:3]:", s[0], s[1], s[2], s[3], s[4])
|
println("cleared s[:3]:", s[0], s[1], s[2], s[3], s[4])
|
||||||
|
|
||||||
|
// The clear builtin, for maps.
|
||||||
|
m := map[int]string{
|
||||||
|
1: "one",
|
||||||
|
2: "two",
|
||||||
|
3: "three",
|
||||||
|
}
|
||||||
|
clear(m)
|
||||||
|
println("cleared map:", m[1], m[2], m[3], len(m))
|
||||||
|
m[4] = "four"
|
||||||
|
println("added to cleared map:", m[1], m[2], m[3], m[4], len(m))
|
||||||
}
|
}
|
||||||
|
|
2
testdata/go1.21.txt
предоставленный
2
testdata/go1.21.txt
предоставленный
|
@ -1,3 +1,5 @@
|
||||||
min/max: -3 5
|
min/max: -3 5
|
||||||
min/max: -3.000000e+000 +5.000000e+000
|
min/max: -3.000000e+000 +5.000000e+000
|
||||||
cleared s[:3]: 0 0 0 4 5
|
cleared s[:3]: 0 0 0 4 5
|
||||||
|
cleared map: 0
|
||||||
|
added to cleared map: four 1
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче