Implement global .data-initalized interfaces
Этот коммит содержится в:
родитель
d13c124df9
коммит
75477eb14e
2 изменённых файлов: 65 добавлений и 50 удалений
107
compiler.go
107
compiler.go
|
@ -759,19 +759,15 @@ func (c *Compiler) getInterpretedValue(value Value) (llvm.Value, error) {
|
|||
return ptr, nil
|
||||
|
||||
case *InterfaceValue:
|
||||
itfTypeNum, ok := c.ir.TypeNum(value.Type)
|
||||
if !ok {
|
||||
panic("interface number is unknown")
|
||||
underlying := llvm.ConstPointerNull(c.i8ptrType) // could be any 0 value
|
||||
if value.Elem != nil {
|
||||
elem, err := c.getInterpretedValue(value.Elem)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
underlying = elem
|
||||
}
|
||||
if itfTypeNum >= 1<<16 {
|
||||
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
|
||||
}
|
||||
fields := []llvm.Value{
|
||||
llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false),
|
||||
llvm.Undef(c.i8ptrType),
|
||||
}
|
||||
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)
|
||||
return itf, nil
|
||||
return c.parseMakeInterface(underlying, value.Type, true)
|
||||
|
||||
case *MapValue:
|
||||
// Create initial bucket.
|
||||
|
@ -1279,6 +1275,8 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
|
|||
return llvm.Value{}, errors.New("unknown basic arg type: " + typ.String())
|
||||
}
|
||||
}
|
||||
case *types.Interface:
|
||||
c.builder.CreateCall(c.mod.NamedFunction("runtime.printitf"), []llvm.Value{value}, "")
|
||||
case *types.Pointer:
|
||||
ptrValue := c.builder.CreatePtrToInt(value, c.uintptrType, "")
|
||||
c.builder.CreateCall(c.mod.NamedFunction("runtime.printptr"), []llvm.Value{ptrValue}, "")
|
||||
|
@ -1639,41 +1637,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
var itfValue llvm.Value
|
||||
size := c.targetData.TypeAllocSize(val.Type())
|
||||
if size > c.targetData.TypeAllocSize(c.i8ptrType) {
|
||||
// Allocate on the heap and put a pointer in the interface.
|
||||
// TODO: escape analysis.
|
||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
|
||||
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(val.Type(), 0), "")
|
||||
c.builder.CreateStore(val, itfValueCast)
|
||||
} else {
|
||||
// Directly place the value in the interface.
|
||||
switch val.Type().TypeKind() {
|
||||
case llvm.IntegerTypeKind:
|
||||
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
|
||||
case llvm.PointerTypeKind:
|
||||
itfValue = c.builder.CreateBitCast(val, c.i8ptrType, "")
|
||||
case llvm.StructTypeKind:
|
||||
// A bitcast would be useful here, but bitcast doesn't allow
|
||||
// aggregate types. So we'll bitcast it using an alloca.
|
||||
// Hopefully this will get optimized away.
|
||||
mem := c.builder.CreateAlloca(c.i8ptrType, "")
|
||||
memStructPtr := c.builder.CreateBitCast(mem, llvm.PointerType(val.Type(), 0), "")
|
||||
c.builder.CreateStore(val, memStructPtr)
|
||||
itfValue = c.builder.CreateLoad(mem, "")
|
||||
default:
|
||||
return llvm.Value{}, errors.New("todo: makeinterface: cast small type to i8*")
|
||||
}
|
||||
}
|
||||
itfTypeNum, _ := c.ir.TypeNum(expr.X.Type())
|
||||
if itfTypeNum >= 1<<16 {
|
||||
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
|
||||
}
|
||||
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), []llvm.Value{llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false), llvm.Undef(c.i8ptrType)})
|
||||
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
||||
return itf, nil
|
||||
return c.parseMakeInterface(val, expr.X.Type(), false)
|
||||
case *ssa.MakeMap:
|
||||
mapType := expr.Type().Underlying().(*types.Map)
|
||||
llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
|
||||
|
@ -2114,6 +2078,55 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value) (
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, isConst bool) (llvm.Value, error) {
|
||||
var itfValue llvm.Value
|
||||
size := c.targetData.TypeAllocSize(val.Type())
|
||||
if size > c.targetData.TypeAllocSize(c.i8ptrType) {
|
||||
if isConst {
|
||||
// Allocate in a global variable.
|
||||
global := llvm.AddGlobal(c.mod, val.Type(), ".itfvalue")
|
||||
global.SetInitializer(val)
|
||||
global.SetLinkage(llvm.PrivateLinkage)
|
||||
global.SetGlobalConstant(true)
|
||||
zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
|
||||
itfValueRaw := llvm.ConstInBoundsGEP(global, []llvm.Value{zero, zero})
|
||||
itfValue = llvm.ConstBitCast(itfValueRaw, c.i8ptrType)
|
||||
} else {
|
||||
// Allocate on the heap and put a pointer in the interface.
|
||||
// TODO: escape analysis.
|
||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
|
||||
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(val.Type(), 0), "")
|
||||
c.builder.CreateStore(val, itfValueCast)
|
||||
}
|
||||
} else {
|
||||
// Directly place the value in the interface.
|
||||
switch val.Type().TypeKind() {
|
||||
case llvm.IntegerTypeKind:
|
||||
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
|
||||
case llvm.PointerTypeKind:
|
||||
itfValue = c.builder.CreateBitCast(val, c.i8ptrType, "")
|
||||
case llvm.StructTypeKind:
|
||||
// A bitcast would be useful here, but bitcast doesn't allow
|
||||
// aggregate types. So we'll bitcast it using an alloca.
|
||||
// Hopefully this will get optimized away.
|
||||
mem := c.builder.CreateAlloca(c.i8ptrType, "")
|
||||
memStructPtr := c.builder.CreateBitCast(mem, llvm.PointerType(val.Type(), 0), "")
|
||||
c.builder.CreateStore(val, memStructPtr)
|
||||
itfValue = c.builder.CreateLoad(mem, "")
|
||||
default:
|
||||
return llvm.Value{}, errors.New("todo: makeinterface: cast small type to i8*")
|
||||
}
|
||||
}
|
||||
itfTypeNum, _ := c.ir.TypeNum(typ)
|
||||
if itfTypeNum >= 1<<16 {
|
||||
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
|
||||
}
|
||||
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), []llvm.Value{llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false), llvm.Undef(c.i8ptrType)})
|
||||
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
||||
return itf, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
|
||||
x, err := c.parseExpr(frame, unop.X)
|
||||
if err != nil {
|
||||
|
|
|
@ -118,6 +118,8 @@ func (p *Program) interpret(instrs []ssa.Instruction) (int, error) {
|
|||
default:
|
||||
panic("expected a pointer")
|
||||
}
|
||||
case *ssa.MakeInterface:
|
||||
locals[instr] = &InterfaceValue{instr.X.Type(), locals[instr.X]}
|
||||
case *ssa.MakeMap:
|
||||
locals[instr] = &MapValue{instr.Type().Underlying().(*types.Map), nil, nil}
|
||||
case *ssa.MapUpdate:
|
||||
|
@ -225,7 +227,7 @@ func (p *Program) getZeroValue(t types.Type) (Value, error) {
|
|||
case *types.Basic:
|
||||
return &ZeroBasicValue{typ}, nil
|
||||
case *types.Interface:
|
||||
return &InterfaceValue{typ}, nil
|
||||
return &InterfaceValue{typ, nil}, nil
|
||||
case *types.Pointer:
|
||||
return &PointerValue{nil}, nil
|
||||
case *types.Struct:
|
||||
|
@ -262,8 +264,8 @@ type PointerValue struct {
|
|||
}
|
||||
|
||||
type InterfaceValue struct {
|
||||
Type *types.Interface
|
||||
//Elem Value
|
||||
Type types.Type
|
||||
Elem Value
|
||||
}
|
||||
|
||||
type PointerBitCastValue struct {
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче