compiler: allow structs in map keys
Этот коммит содержится в:
родитель
c0c1ccb381
коммит
77d6d6c417
1 изменённых файлов: 71 добавлений и 60 удалений
131
compiler/map.go
131
compiler/map.go
|
@ -10,76 +10,68 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Value) (llvm.Value, error) {
|
func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Value) (llvm.Value, error) {
|
||||||
switch keyType := keyType.Underlying().(type) {
|
llvmValueType, err := c.getLLVMType(valueType)
|
||||||
case *types.Basic:
|
if err != nil {
|
||||||
llvmValueType, err := c.getLLVMType(valueType)
|
return llvm.Value{}, err
|
||||||
if err != nil {
|
}
|
||||||
return llvm.Value{}, err
|
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
|
||||||
}
|
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
|
||||||
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
|
// key is a string
|
||||||
if keyType.Info()&types.IsString != 0 {
|
params := []llvm.Value{m, key, mapValuePtr}
|
||||||
params := []llvm.Value{m, key, mapValuePtr}
|
c.createRuntimeCall("hashmapStringGet", params, "")
|
||||||
c.createRuntimeCall("hashmapStringGet", params, "")
|
return c.builder.CreateLoad(mapValueAlloca, ""), nil
|
||||||
return c.builder.CreateLoad(mapValueAlloca, ""), nil
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
} else if keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 {
|
// key can be compared with runtime.memequal
|
||||||
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
||||||
c.builder.CreateStore(key, keyAlloca)
|
c.builder.CreateStore(key, keyAlloca)
|
||||||
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
||||||
params := []llvm.Value{m, keyPtr, mapValuePtr}
|
params := []llvm.Value{m, keyPtr, mapValuePtr}
|
||||||
c.createRuntimeCall("hashmapBinaryGet", params, "")
|
c.createRuntimeCall("hashmapBinaryGet", params, "")
|
||||||
return c.builder.CreateLoad(mapValueAlloca, ""), nil
|
return c.builder.CreateLoad(mapValueAlloca, ""), nil
|
||||||
} else {
|
} else {
|
||||||
return llvm.Value{}, errors.New("todo: map lookup key type: " + keyType.String())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return llvm.Value{}, errors.New("todo: map lookup key type: " + keyType.String())
|
return llvm.Value{}, errors.New("todo: map lookup key type: " + keyType.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value) error {
|
func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value) error {
|
||||||
switch keyType := keyType.Underlying().(type) {
|
valueAlloca := c.builder.CreateAlloca(value.Type(), "hashmap.value")
|
||||||
case *types.Basic:
|
c.builder.CreateStore(value, valueAlloca)
|
||||||
valueAlloca := c.builder.CreateAlloca(value.Type(), "hashmap.value")
|
valuePtr := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "hashmap.valueptr")
|
||||||
c.builder.CreateStore(value, valueAlloca)
|
keyType = keyType.Underlying()
|
||||||
valuePtr := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "hashmap.valueptr")
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
if keyType.Info()&types.IsString != 0 {
|
// key is a string
|
||||||
params := []llvm.Value{m, key, valuePtr}
|
params := []llvm.Value{m, key, valuePtr}
|
||||||
c.createRuntimeCall("hashmapStringSet", params, "")
|
c.createRuntimeCall("hashmapStringSet", params, "")
|
||||||
return nil
|
return nil
|
||||||
} else if keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
// key can be compared with runtime.memequal
|
||||||
c.builder.CreateStore(key, keyAlloca)
|
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
||||||
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
c.builder.CreateStore(key, keyAlloca)
|
||||||
params := []llvm.Value{m, keyPtr, valuePtr}
|
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
||||||
c.createRuntimeCall("hashmapBinarySet", params, "")
|
params := []llvm.Value{m, keyPtr, valuePtr}
|
||||||
return nil
|
c.createRuntimeCall("hashmapBinarySet", params, "")
|
||||||
} else {
|
return nil
|
||||||
return errors.New("todo: map update key type: " + keyType.String())
|
} else {
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("todo: map update key type: " + keyType.String())
|
return errors.New("todo: map update key type: " + keyType.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value) error {
|
func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value) error {
|
||||||
switch keyType := keyType.Underlying().(type) {
|
keyType = keyType.Underlying()
|
||||||
case *types.Basic:
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
if keyType.Info()&types.IsString != 0 {
|
// key is a string
|
||||||
params := []llvm.Value{m, key}
|
params := []llvm.Value{m, key}
|
||||||
c.createRuntimeCall("hashmapStringDelete", params, "")
|
c.createRuntimeCall("hashmapStringDelete", params, "")
|
||||||
return nil
|
return nil
|
||||||
} else if keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key")
|
||||||
c.builder.CreateStore(key, keyAlloca)
|
c.builder.CreateStore(key, keyAlloca)
|
||||||
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr")
|
||||||
params := []llvm.Value{m, keyPtr}
|
params := []llvm.Value{m, keyPtr}
|
||||||
c.createRuntimeCall("hashmapBinaryDelete", params, "")
|
c.createRuntimeCall("hashmapBinaryDelete", params, "")
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return errors.New("todo: map lookup key type: " + keyType.String())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("todo: map delete key type: " + keyType.String())
|
return errors.New("todo: map delete key type: " + keyType.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,3 +97,22 @@ func hashmapTopHash(hash uint32) uint8 {
|
||||||
}
|
}
|
||||||
return tophash
|
return tophash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if this key type does not contain strings, interfaces etc., so
|
||||||
|
// can be compared with runtime.memequal.
|
||||||
|
func hashmapIsBinaryKey(keyType types.Type) bool {
|
||||||
|
switch keyType := keyType.(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
|
||||||
|
case *types.Struct:
|
||||||
|
for i := 0; i < keyType.NumFields(); i++ {
|
||||||
|
fieldType := keyType.Field(i).Type().Underlying()
|
||||||
|
if !hashmapIsBinaryKey(fieldType) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче