11package compiler
22
3+ //go:generate go run ./mkruntimetypes.go
4+
35import (
46 "debug/dwarf"
57 "errors"
@@ -49,11 +51,14 @@ type compilerContext struct {
4951 targetData llvm.TargetData
5052 intType llvm.Type
5153 i8ptrType llvm.Type // for convenience
54+ runtimeTypes map [string ]types.Type
5255 funcPtrAddrSpace int
5356 uintptrType llvm.Type
5457 program * ssa.Program
5558 diagnostics []error
5659 astComments map [string ]* ast.CommentGroup
60+ runtimePkg * types.Package // package runtime
61+ taskPkg * types.Package // package internal/task
5762}
5863
5964// builder contains all information relevant to build a single function.
@@ -101,11 +106,12 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
101106// configuration, ready to compile Go SSA to LLVM IR.
102107func newCompilerContext (pkgName string , machine llvm.TargetMachine , config * compileopts.Config ) * compilerContext {
103108 c := & compilerContext {
104- Config : config ,
105- difiles : make (map [string ]llvm.Metadata ),
106- ditypes : make (map [types.Type ]llvm.Metadata ),
107- machine : machine ,
108- targetData : machine .CreateTargetData (),
109+ Config : config ,
110+ difiles : make (map [string ]llvm.Metadata ),
111+ ditypes : make (map [types.Type ]llvm.Metadata ),
112+ machine : machine ,
113+ targetData : machine .CreateTargetData (),
114+ runtimeTypes : make (map [string ]types.Type ),
109115 }
110116
111117 c .ctx = llvm .NewContext ()
@@ -246,6 +252,8 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
246252
247253 c .program = lprogram .LoadSSA ()
248254 c .program .Build ()
255+ c .runtimePkg = c .program .ImportedPackage ("runtime" ).Pkg
256+ c .taskPkg = c .program .ImportedPackage ("internal/task" ).Pkg
249257
250258 // Initialize debug information.
251259 if c .Debug () {
@@ -260,20 +268,6 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
260268
261269 c .loadASTComments (lprogram )
262270
263- // Declare runtime types.
264- // TODO: lazily create runtime types in getLLVMRuntimeType when they are
265- // needed. Eventually this will be required anyway, when packages are
266- // compiled independently (and the runtime types are not available).
267- for _ , member := range c .program .ImportedPackage ("runtime" ).Members {
268- if member , ok := member .(* ssa.Type ); ok {
269- if typ , ok := member .Type ().(* types.Named ); ok {
270- if _ , ok := typ .Underlying ().(* types.Struct ); ok {
271- c .getLLVMType (typ )
272- }
273- }
274- }
275- }
276-
277271 // Predeclare the runtime.alloc function, which is used by the wordpack
278272 // functionality.
279273 c .getFunction (c .program .ImportedPackage ("runtime" ).Members ["alloc" ].(* ssa.Function ))
@@ -453,16 +447,14 @@ func sortPackages(program *ssa.Program, mainPath string) []*ssa.Package {
453447}
454448
455449// getLLVMRuntimeType obtains a named type from the runtime package and returns
456- // it as a LLVM type, creating it if necessary. It is a shorthand for
457- // getLLVMType(getRuntimeType(name)).
450+ // it as a LLVM type, creating it if necessary.
458451func (c * compilerContext ) getLLVMRuntimeType (name string ) llvm.Type {
459452 fullName := "runtime." + name
460- typ := c .mod .GetTypeByName (fullName )
461- if typ .IsNil () {
462- println (c .mod .String ())
463- panic ("could not find runtime type: " + fullName )
453+ llvmType := c .mod .GetTypeByName (fullName )
454+ if llvmType .IsNil () {
455+ llvmType = c .getLLVMType (c .getRuntimeType (name ))
464456 }
465- return typ
457+ return llvmType
466458}
467459
468460// getLLVMType creates and returns a LLVM type for a Go type. In the case of
@@ -522,6 +514,10 @@ func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
522514 llvmType = c .ctx .StructCreateNamed (llvmName )
523515 underlying := c .getLLVMType (st )
524516 llvmType .StructSetBody (underlying .StructElementTypes (), false )
517+ } else if typ .String () == "internal/task.Task" && llvmType .StructElementTypesCount () == 0 {
518+ // Note: this struct is an opaque struct. Give it a body.
519+ underlying := c .getLLVMType (st )
520+ llvmType .StructSetBody (underlying .StructElementTypes (), false )
525521 }
526522 return llvmType
527523 }
@@ -542,6 +538,23 @@ func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
542538 case * types.Struct :
543539 members := make ([]llvm.Type , typ .NumFields ())
544540 for i := 0 ; i < typ .NumFields (); i ++ {
541+ if ptr , ok := typ .Field (i ).Type ().(* types.Pointer ); ok {
542+ if named , ok := ptr .Elem ().(* types.Named ); ok && named .String () == "internal/task.Task" {
543+ // Special workaround for internal/task.Task. It is
544+ // referenced from the runtime.channel type, which
545+ // references runtime.channelBlockedList, which references
546+ // internal/task.Task. To avoid having to define
547+ // internal/task.Task as a compiler-internal type, make the
548+ // type opaque.
549+ ptrTo := c .mod .GetTypeByName (named .String ())
550+ if ptrTo .IsNil () {
551+ ptrTo = c .ctx .StructCreateNamed (named .String ())
552+ }
553+ members [i ] = llvm .PointerType (ptrTo , 0 )
554+ continue
555+ }
556+ }
557+
545558 members [i ] = c .getLLVMType (typ .Field (i ).Type ())
546559 }
547560 return c .ctx .StructType (members , false )
@@ -645,11 +658,11 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
645658 Encoding : encoding ,
646659 })
647660 case * types.Chan :
648- return c .getDIType (types .NewPointer (c .program . ImportedPackage ( "runtime" ). Members [ " channel"].( * ssa. Type ). Type ( )))
661+ return c .getDIType (types .NewPointer (c .getRuntimeType ( " channel" )))
649662 case * types.Interface :
650- return c .getDIType (c .program . ImportedPackage ( "runtime" ). Members [ " _interface"].( * ssa. Type ). Type ( ))
663+ return c .getDIType (c .getRuntimeType ( " _interface" ))
651664 case * types.Map :
652- return c .getDIType (types .NewPointer (c .program . ImportedPackage ( "runtime" ). Members [ " hashmap"].( * ssa. Type ). Type ( )))
665+ return c .getDIType (types .NewPointer (c .getRuntimeType ( " hashmap" )))
653666 case * types.Named :
654667 return c .dibuilder .CreateTypedef (llvm.DITypedef {
655668 Type : c .getDIType (typ .Underlying ()),
0 commit comments