diff options
-rw-r--r-- | compiler/channel.go | 2 | ||||
-rw-r--r-- | compiler/compiler.go | 66 | ||||
-rw-r--r-- | compiler/defer.go | 8 | ||||
-rw-r--r-- | compiler/func-lowering.go | 2 | ||||
-rw-r--r-- | compiler/func.go | 4 | ||||
-rw-r--r-- | compiler/goroutine-lowering.go | 2 | ||||
-rw-r--r-- | compiler/interface-lowering.go | 4 | ||||
-rw-r--r-- | compiler/interface.go | 10 | ||||
-rw-r--r-- | ir/ir.go | 16 |
9 files changed, 51 insertions, 63 deletions
diff --git a/compiler/channel.go b/compiler/channel.go index b5bcd95b9..8098ea99a 100644 --- a/compiler/channel.go +++ b/compiler/channel.go @@ -12,7 +12,7 @@ import ( // emitMakeChan returns a new channel value for the given channel type. func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) { - chanType := c.mod.GetTypeByName("runtime.channel") + chanType := c.getLLVMType(c.getRuntimeType("channel")) size := c.targetData.TypeAllocSize(chanType) sizeValue := llvm.ConstInt(c.uintptrType, size, false) ptr := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "chan.alloc") diff --git a/compiler/compiler.go b/compiler/compiler.go index 821b6270c..1c22208cc 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -275,25 +275,6 @@ func (c *Compiler) Compile(mainPath string) []error { var frames []*Frame - // Declare all named struct types. - for _, t := range c.ir.NamedTypes { - if named, ok := t.Type.Type().(*types.Named); ok { - if _, ok := named.Underlying().(*types.Struct); ok { - t.LLVMType = c.ctx.StructCreateNamed(named.Obj().Pkg().Path() + "." + named.Obj().Name()) - } - } - } - - // Define all named struct types. - for _, t := range c.ir.NamedTypes { - if named, ok := t.Type.Type().(*types.Named); ok { - if st, ok := named.Underlying().(*types.Struct); ok { - llvmType := c.getLLVMType(st) - t.LLVMType.StructSetBody(llvmType.StructElementTypes(), false) - } - } - } - // Declare all globals. for _, g := range c.ir.Globals { typ := g.Type().(*types.Pointer).Elem() @@ -413,6 +394,22 @@ func (c *Compiler) Compile(mainPath string) []error { return c.diagnostics } +// getRuntimeType obtains a named type from the runtime package and returns it +// as a Go type. +func (c *Compiler) getRuntimeType(name string) types.Type { + return c.ir.Program.ImportedPackage("runtime").Type(name).Type() +} + +// getLLVMRuntimeType obtains a named type from the runtime package and returns +// it as a LLVM type, creating it if necessary. It is a shorthand for +// getLLVMType(getRuntimeType(name)). +func (c *Compiler) getLLVMRuntimeType(name string) llvm.Type { + return c.getLLVMType(c.getRuntimeType(name)) +} + +// getLLVMType creates and returns a LLVM type for a Go type. In the case of +// named struct types (or Go types implemented as named LLVM structs such as +// strings) it also creates it first if necessary. func (c *Compiler) getLLVMType(goType types.Type) llvm.Type { switch typ := goType.(type) { case *types.Array: @@ -441,7 +438,7 @@ func (c *Compiler) getLLVMType(goType types.Type) llvm.Type { case types.Complex128: return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false) case types.String, types.UntypedString: - return c.mod.GetTypeByName("runtime._string") + return c.getLLVMRuntimeType("_string") case types.Uintptr: return c.uintptrType case types.UnsafePointer: @@ -450,16 +447,23 @@ func (c *Compiler) getLLVMType(goType types.Type) llvm.Type { panic("unknown basic type: " + typ.String()) } case *types.Chan: - return llvm.PointerType(c.mod.GetTypeByName("runtime.channel"), 0) + return llvm.PointerType(c.getLLVMRuntimeType("channel"), 0) case *types.Interface: - return c.mod.GetTypeByName("runtime._interface") + return c.getLLVMRuntimeType("_interface") case *types.Map: - return llvm.PointerType(c.mod.GetTypeByName("runtime.hashmap"), 0) + return llvm.PointerType(c.getLLVMRuntimeType("hashmap"), 0) case *types.Named: - if _, ok := typ.Underlying().(*types.Struct); ok { - llvmType := c.mod.GetTypeByName(typ.Obj().Pkg().Path() + "." + typ.Obj().Name()) + if st, ok := typ.Underlying().(*types.Struct); ok { + // Structs are a special case. While other named types are ignored + // in LLVM IR, named structs are implemented as named structs in + // LLVM. This is because it is otherwise impossible to create + // self-referencing types such as linked lists. + llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name() + llvmType := c.mod.GetTypeByName(llvmName) if llvmType.IsNil() { - panic("underlying type not found: " + typ.Obj().Pkg().Path() + "." + typ.Obj().Name()) + llvmType = c.ctx.StructCreateNamed(llvmName) + underlying := c.getLLVMType(st) + llvmType.StructSetBody(underlying.StructElementTypes(), false) } return llvmType } @@ -1693,9 +1697,9 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { var iteratorType llvm.Type switch typ := expr.X.Type().Underlying().(type) { case *types.Basic: // string - iteratorType = c.mod.GetTypeByName("runtime.stringIterator") + iteratorType = c.getLLVMRuntimeType("stringIterator") case *types.Map: - iteratorType = c.mod.GetTypeByName("runtime.hashmapIterator") + iteratorType = c.getLLVMRuntimeType("hashmapIterator") default: panic("unknown type in range: " + typ.String()) } @@ -1855,7 +1859,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "") newLen := c.builder.CreateSub(high, low, "") - str := llvm.Undef(c.mod.GetTypeByName("runtime._string")) + str := llvm.Undef(c.getLLVMRuntimeType("_string")) str = c.builder.CreateInsertValue(str, newPtr, 0, "") str = c.builder.CreateInsertValue(str, newLen, 1, "") return str, nil @@ -2234,7 +2238,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value { global.SetUnnamedAddr(true) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) strPtr := c.builder.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "") - strObj := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._string"), []llvm.Value{strPtr, strLen}) + strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen}) return strObj } else if typ.Kind() == types.UnsafePointer { if !expr.IsNil() { @@ -2287,7 +2291,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value { llvm.ConstInt(c.uintptrType, 0, false), llvm.ConstPointerNull(c.i8ptrType), } - return llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields) + return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields) case *types.Pointer: if expr.Value != nil { panic("expected nil pointer constant") diff --git a/compiler/defer.go b/compiler/defer.go index 1246f03a0..21fff3aad 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -29,7 +29,7 @@ func (c *Compiler) deferInitFunc(frame *Frame) { frame.deferClosureFuncs = make(map[*ir.Function]int) // Create defer list pointer. - deferType := llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0) + deferType := llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0) frame.deferPtr = c.builder.CreateAlloca(deferType, "deferPtr") c.builder.CreateStore(llvm.ConstPointerNull(deferType), frame.deferPtr) } @@ -200,7 +200,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) { } // Get the real defer struct type and cast to it. - valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0), c.i8ptrType} + valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0), c.i8ptrType} for _, arg := range callback.Args { valueTypes = append(valueTypes, c.getLLVMType(arg.Type())) } @@ -231,7 +231,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) { // Direct call. // Get the real defer struct type and cast to it. - valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)} + valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0)} for _, param := range callback.Params { valueTypes = append(valueTypes, c.getLLVMType(param.Type())) } @@ -260,7 +260,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) { case *ssa.MakeClosure: // Get the real defer struct type and cast to it. fn := c.ir.GetFunction(callback.Fn.(*ssa.Function)) - valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)} + valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0)} params := fn.Signature.Params() for i := 0; i < params.Len(); i++ { valueTypes = append(valueTypes, c.getLLVMType(params.At(i).Type())) diff --git a/compiler/func-lowering.go b/compiler/func-lowering.go index a774b23ac..2d67e2a5f 100644 --- a/compiler/func-lowering.go +++ b/compiler/func-lowering.go @@ -51,7 +51,7 @@ func (c *Compiler) LowerFuncValues() { } // Find all func values used in the program with their signatures. - funcValueWithSignaturePtr := llvm.PointerType(c.mod.GetTypeByName("runtime.funcValueWithSignature"), 0) + funcValueWithSignaturePtr := llvm.PointerType(c.getLLVMRuntimeType("funcValueWithSignature"), 0) signatures := map[string]*funcSignatureInfo{} for global := c.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) { if global.Type() != funcValueWithSignaturePtr { diff --git a/compiler/func.go b/compiler/func.go index 8a2e1ab39..c4806a09d 100644 --- a/compiler/func.go +++ b/compiler/func.go @@ -52,7 +52,7 @@ func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signa funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature" funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName) if funcValueWithSignatureGlobal.IsNil() { - funcValueWithSignatureType := c.mod.GetTypeByName("runtime.funcValueWithSignature") + funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature") funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{ llvm.ConstPtrToInt(funcPtr, c.uintptrType), sigGlobal, @@ -126,7 +126,7 @@ func (c *Compiler) getFuncType(typ *types.Signature) llvm.Type { rawPtr := c.getRawFuncType(typ) return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false) case funcValueSwitch: - return c.mod.GetTypeByName("runtime.funcValue") + return c.getLLVMRuntimeType("funcValue") default: panic("unimplemented func value variant") } diff --git a/compiler/goroutine-lowering.go b/compiler/goroutine-lowering.go index c493bf48c..3aa72e938 100644 --- a/compiler/goroutine-lowering.go +++ b/compiler/goroutine-lowering.go @@ -321,7 +321,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) { // Coroutine setup. c.builder.SetInsertPointBefore(f.EntryBasicBlock().FirstInstruction()) - taskState := c.builder.CreateAlloca(c.mod.GetTypeByName("runtime.taskState"), "task.state") + taskState := c.builder.CreateAlloca(c.getLLVMRuntimeType("taskState"), "task.state") stateI8 := c.builder.CreateBitCast(taskState, c.i8ptrType, "task.state.i8") id := c.builder.CreateCall(coroIdFunc, []llvm.Value{ llvm.ConstInt(c.ctx.Int32Type(), 0, false), diff --git a/compiler/interface-lowering.go b/compiler/interface-lowering.go index 3df1c6443..6a756410c 100644 --- a/compiler/interface-lowering.go +++ b/compiler/interface-lowering.go @@ -163,8 +163,8 @@ func (c *Compiler) LowerInterfaces() { // run runs the pass itself. func (p *lowerInterfacesPass) run() { // Collect all type codes. - typecodeIDPtr := llvm.PointerType(p.mod.GetTypeByName("runtime.typecodeID"), 0) - typeInInterfacePtr := llvm.PointerType(p.mod.GetTypeByName("runtime.typeInInterface"), 0) + typecodeIDPtr := llvm.PointerType(p.getLLVMRuntimeType("typecodeID"), 0) + typeInInterfacePtr := llvm.PointerType(p.getLLVMRuntimeType("typeInInterface"), 0) var typesInInterfaces []llvm.Value for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) { switch global.Type() { diff --git a/compiler/interface.go b/compiler/interface.go index 3d2014f31..d91b8063f 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -28,14 +28,14 @@ func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, pos token. itfMethodSetGlobal := c.getTypeMethodSet(typ) itfConcreteTypeGlobal := c.mod.NamedGlobal("typeInInterface:" + itfTypeCodeGlobal.Name()) if itfConcreteTypeGlobal.IsNil() { - typeInInterface := c.mod.GetTypeByName("runtime.typeInInterface") + typeInInterface := c.getLLVMRuntimeType("typeInInterface") itfConcreteTypeGlobal = llvm.AddGlobal(c.mod, typeInInterface, "typeInInterface:"+itfTypeCodeGlobal.Name()) itfConcreteTypeGlobal.SetInitializer(llvm.ConstNamedStruct(typeInInterface, []llvm.Value{itfTypeCodeGlobal, itfMethodSetGlobal})) itfConcreteTypeGlobal.SetGlobalConstant(true) itfConcreteTypeGlobal.SetLinkage(llvm.PrivateLinkage) } itfTypeCode := c.builder.CreatePtrToInt(itfConcreteTypeGlobal, c.uintptrType, "") - itf := llvm.Undef(c.mod.GetTypeByName("runtime._interface")) + itf := llvm.Undef(c.getLLVMRuntimeType("_interface")) itf = c.builder.CreateInsertValue(itf, itfTypeCode, 0, "") itf = c.builder.CreateInsertValue(itf, itfValue, 1, "") return itf @@ -48,7 +48,7 @@ func (c *Compiler) getTypeCode(typ types.Type) llvm.Value { globalName := "type:" + getTypeCodeName(typ) global := c.mod.NamedGlobal(globalName) if global.IsNil() { - global = llvm.AddGlobal(c.mod, c.mod.GetTypeByName("runtime.typecodeID"), globalName) + global = llvm.AddGlobal(c.mod, c.getLLVMRuntimeType("typecodeID"), globalName) global.SetGlobalConstant(true) } return global @@ -163,11 +163,11 @@ func (c *Compiler) getTypeMethodSet(typ types.Type) llvm.Value { ms := c.ir.Program.MethodSets.MethodSet(typ) if ms.Len() == 0 { // no methods, so can leave that one out - return llvm.ConstPointerNull(llvm.PointerType(c.mod.GetTypeByName("runtime.interfaceMethodInfo"), 0)) + return llvm.ConstPointerNull(llvm.PointerType(c.getLLVMRuntimeType("interfaceMethodInfo"), 0)) } methods := make([]llvm.Value, ms.Len()) - interfaceMethodInfoType := c.mod.GetTypeByName("runtime.interfaceMethodInfo") + interfaceMethodInfoType := c.getLLVMRuntimeType("interfaceMethodInfo") for i := 0; i < ms.Len(); i++ { method := ms.At(i) signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func)) @@ -26,7 +26,6 @@ type Program struct { Globals []*Global globalMap map[*ssa.Global]*Global comments map[string]*ast.CommentGroup - NamedTypes []*NamedType } // Function or method. @@ -50,19 +49,6 @@ type Global struct { extern bool // go:extern } -// Type with a name and possibly methods. -type NamedType struct { - *ssa.Type - LLVMType llvm.Type -} - -// Type that is at some point put in an interface. -type TypeWithMethods struct { - t types.Type - Num int - Methods map[string]*types.Selection -} - // Interface type that is at some point used in a type assert (to check whether // it implements another interface). type Interface struct { @@ -210,8 +196,6 @@ func (p *Program) AddPackage(pkg *ssa.Package) { case *ssa.Function: p.addFunction(member) case *ssa.Type: - t := &NamedType{Type: member} - p.NamedTypes = append(p.NamedTypes, t) methods := getAllMethods(pkg.Prog, member.Type()) if !types.IsInterface(member.Type()) { // named type |