Implement global .data-initalized interfaces

Этот коммит содержится в:
Ayke van Laethem 2018-08-30 02:08:00 +02:00
родитель d13c124df9
коммит 75477eb14e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
2 изменённых файлов: 65 добавлений и 50 удалений

Просмотреть файл

@ -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
}
if itfTypeNum >= 1<<16 {
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
underlying = elem
}
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 {