@@ -18,7 +18,6 @@ import (
1818 "github.com/tinygo-org/tinygo/compileopts"
1919 "github.com/tinygo-org/tinygo/compiler/llvmutil"
2020 "github.com/tinygo-org/tinygo/goenv"
21- "github.com/tinygo-org/tinygo/ir"
2221 "github.com/tinygo-org/tinygo/loader"
2322 "golang.org/x/tools/go/ssa"
2423 "tinygo.org/x/go-llvm"
@@ -52,7 +51,7 @@ type compilerContext struct {
5251 i8ptrType llvm.Type // for convenience
5352 funcPtrAddrSpace int
5453 uintptrType llvm.Type
55- ir * ir .Program
54+ program * ssa .Program
5655 diagnostics []error
5756 astComments map [string ]* ast.CommentGroup
5857}
@@ -245,7 +244,8 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
245244 return c .mod , nil , []error {err }
246245 }
247246
248- c .ir = ir .NewProgram (lprogram , pkgName )
247+ c .program = lprogram .LoadSSA ()
248+ c .program .Build ()
249249
250250 // Initialize debug information.
251251 if c .Debug () {
@@ -264,7 +264,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
264264 // TODO: lazily create runtime types in getLLVMRuntimeType when they are
265265 // needed. Eventually this will be required anyway, when packages are
266266 // compiled independently (and the runtime types are not available).
267- for _ , member := range c .ir . Program .ImportedPackage ("runtime" ).Members {
267+ for _ , member := range c .program .ImportedPackage ("runtime" ).Members {
268268 if member , ok := member .(* ssa.Type ); ok {
269269 if typ , ok := member .Type ().(* types.Named ); ok {
270270 if _ , ok := typ .Underlying ().(* types.Struct ); ok {
@@ -276,11 +276,13 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
276276
277277 // Predeclare the runtime.alloc function, which is used by the wordpack
278278 // functionality.
279- c .getFunction (c .ir .Program .ImportedPackage ("runtime" ).Members ["alloc" ].(* ssa.Function ))
279+ c .getFunction (c .program .ImportedPackage ("runtime" ).Members ["alloc" ].(* ssa.Function ))
280+
281+ sortedPackages := sortPackages (c .program , pkgName )
280282
281283 // Find package initializers.
282284 var initFuncs []llvm.Value
283- for _ , pkg := range c . ir . Packages () {
285+ for _ , pkg := range sortedPackages {
284286 for _ , member := range pkg .Members {
285287 switch member := member .(type ) {
286288 case * ssa.Function :
@@ -294,19 +296,19 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
294296 // Add definitions to declarations.
295297 irbuilder := c .ctx .NewBuilder ()
296298 defer irbuilder .Dispose ()
297- for _ , pkg := range c . ir . Packages () {
299+ for _ , pkg := range sortedPackages {
298300 c .createPackage (pkg , irbuilder )
299301 }
300302
301303 // After all packages are imported, add a synthetic initializer function
302304 // that calls the initializer of each package.
303- initFn := c .ir . Program .ImportedPackage ("runtime" ).Members ["initAll" ].(* ssa.Function )
305+ initFn := c .program .ImportedPackage ("runtime" ).Members ["initAll" ].(* ssa.Function )
304306 llvmInitFn := c .getFunction (initFn )
305307 llvmInitFn .SetLinkage (llvm .InternalLinkage )
306308 llvmInitFn .SetUnnamedAddr (true )
307309 if c .Debug () {
308310 difunc := c .attachDebugInfo (initFn )
309- pos := c .ir . Program .Fset .Position (initFn .Pos ())
311+ pos := c .program .Fset .Position (initFn .Pos ())
310312 irbuilder .SetCurrentDebugLocation (uint (pos .Line ), uint (pos .Column ), difunc , llvm.Metadata {})
311313 }
312314 block := c .ctx .AddBasicBlock (llvmInitFn , "entry" )
@@ -318,7 +320,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
318320
319321 // Conserve for goroutine lowering. Without marking these as external, they
320322 // would be optimized away.
321- realMain := c .mod .NamedFunction (c . ir . MainPkg (). Pkg . Path () + ".main" )
323+ realMain := c .mod .NamedFunction (pkgName + ".main" )
322324 realMain .SetLinkage (llvm .ExternalLinkage ) // keep alive until goroutine lowering
323325
324326 // Replace callMain placeholder with actual main function.
@@ -374,7 +376,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
374376
375377 // Gather the list of (C) file paths that should be included in the build.
376378 var extraFiles []string
377- for _ , pkg := range c . ir . LoaderProgram .Sorted () {
379+ for _ , pkg := range lprogram .Sorted () {
378380 for _ , file := range pkg .CFiles {
379381 extraFiles = append (extraFiles , filepath .Join (pkg .Package .Dir , file ))
380382 }
@@ -383,6 +385,73 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
383385 return c .mod , extraFiles , c .diagnostics
384386}
385387
388+ // sortPackages returns a list of all packages, sorted by import order.
389+ func sortPackages (program * ssa.Program , mainPath string ) []* ssa.Package {
390+ // Find the main package, which is a bit difficult when running a .go file
391+ // directly.
392+ mainPkg := program .ImportedPackage (mainPath )
393+ if mainPkg == nil {
394+ for _ , pkgInfo := range program .AllPackages () {
395+ if pkgInfo .Pkg .Name () == "main" {
396+ if mainPkg != nil {
397+ panic ("more than one main package found" )
398+ }
399+ mainPkg = pkgInfo
400+ }
401+ }
402+ }
403+ if mainPkg == nil {
404+ panic ("could not find main package" )
405+ }
406+
407+ packageList := []* ssa.Package {}
408+ packageSet := map [string ]struct {}{}
409+ worklist := []string {"runtime" , mainPath }
410+ for len (worklist ) != 0 {
411+ pkgPath := worklist [0 ]
412+ var pkg * ssa.Package
413+ if pkgPath == mainPath {
414+ pkg = mainPkg // necessary for compiling individual .go files
415+ } else {
416+ pkg = program .ImportedPackage (pkgPath )
417+ }
418+ if pkg == nil {
419+ // Non-SSA package (e.g. cgo).
420+ packageSet [pkgPath ] = struct {}{}
421+ worklist = worklist [1 :]
422+ continue
423+ }
424+ if _ , ok := packageSet [pkgPath ]; ok {
425+ // Package already in the final package list.
426+ worklist = worklist [1 :]
427+ continue
428+ }
429+
430+ unsatisfiedImports := make ([]string , 0 )
431+ imports := pkg .Pkg .Imports ()
432+ for _ , pkg := range imports {
433+ if _ , ok := packageSet [pkg .Path ()]; ok {
434+ continue
435+ }
436+ unsatisfiedImports = append (unsatisfiedImports , pkg .Path ())
437+ }
438+ if len (unsatisfiedImports ) == 0 {
439+ // All dependencies of this package are satisfied, so add this
440+ // package to the list.
441+ packageList = append (packageList , pkg )
442+ packageSet [pkgPath ] = struct {}{}
443+ worklist = worklist [1 :]
444+ } else {
445+ // Prepend all dependencies to the worklist and reconsider this
446+ // package (by not removing it from the worklist). At that point, it
447+ // must be possible to add it to packageList.
448+ worklist = append (unsatisfiedImports , worklist ... )
449+ }
450+ }
451+
452+ return packageList
453+ }
454+
386455// getLLVMRuntimeType obtains a named type from the runtime package and returns
387456// it as a LLVM type, creating it if necessary. It is a shorthand for
388457// getLLVMType(getRuntimeType(name)).
@@ -576,11 +645,11 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
576645 Encoding : encoding ,
577646 })
578647 case * types.Chan :
579- return c .getDIType (types .NewPointer (c .ir . Program .ImportedPackage ("runtime" ).Members ["channel" ].(* ssa.Type ).Type ()))
648+ return c .getDIType (types .NewPointer (c .program .ImportedPackage ("runtime" ).Members ["channel" ].(* ssa.Type ).Type ()))
580649 case * types.Interface :
581- return c .getDIType (c .ir . Program .ImportedPackage ("runtime" ).Members ["_interface" ].(* ssa.Type ).Type ())
650+ return c .getDIType (c .program .ImportedPackage ("runtime" ).Members ["_interface" ].(* ssa.Type ).Type ())
582651 case * types.Map :
583- return c .getDIType (types .NewPointer (c .ir . Program .ImportedPackage ("runtime" ).Members ["hashmap" ].(* ssa.Type ).Type ()))
652+ return c .getDIType (types .NewPointer (c .program .ImportedPackage ("runtime" ).Members ["hashmap" ].(* ssa.Type ).Type ()))
584653 case * types.Named :
585654 return c .dibuilder .CreateTypedef (llvm.DITypedef {
586655 Type : c .getDIType (typ .Underlying ()),
@@ -688,7 +757,7 @@ func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
688757 return dilocal
689758 }
690759
691- pos := b .ir . Program .Fset .Position (variable .Pos ())
760+ pos := b .program .Fset .Position (variable .Pos ())
692761
693762 // Check whether this is a function parameter.
694763 for i , param := range b .fn .Params {
@@ -722,7 +791,7 @@ func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
722791// attachDebugInfo adds debug info to a function declaration. It returns the
723792// DISubprogram metadata node.
724793func (c * compilerContext ) attachDebugInfo (f * ssa.Function ) llvm.Metadata {
725- pos := c .ir . Program .Fset .Position (f .Syntax ().Pos ())
794+ pos := c .program .Fset .Position (f .Syntax ().Pos ())
726795 return c .attachDebugInfoRaw (f , c .getFunction (f ), "" , pos .Filename , pos .Line )
727796}
728797
@@ -876,7 +945,7 @@ func (c *compilerContext) createFunction(irbuilder llvm.Builder, fn *ssa.Functio
876945 // Create debug info file if needed.
877946 b .difunc = b .attachDebugInfo (b .fn )
878947 }
879- pos := b .ir . Program .Fset .Position (b .fn .Pos ())
948+ pos := b .program .Fset .Position (b .fn .Pos ())
880949 b .SetCurrentDebugLocation (uint (pos .Line ), uint (pos .Column ), b .difunc , llvm.Metadata {})
881950 }
882951
@@ -978,7 +1047,7 @@ func (c *compilerContext) createFunction(irbuilder llvm.Builder, fn *ssa.Functio
9781047 continue
9791048 }
9801049 dbgVar := b .getLocalVariable (variable )
981- pos := b .ir . Program .Fset .Position (instr .Pos ())
1050+ pos := b .program .Fset .Position (instr .Pos ())
9821051 b .dibuilder .InsertValueAtEnd (b .getValue (instr .X ), dbgVar , b .dibuilder .CreateExpression (nil ), llvm.DebugLoc {
9831052 Line : uint (pos .Line ),
9841053 Col : uint (pos .Column ),
@@ -1032,7 +1101,7 @@ func (c *compilerContext) createFunction(irbuilder llvm.Builder, fn *ssa.Functio
10321101// particular Go SSA instruction.
10331102func (b * builder ) createInstruction (instr ssa.Instruction ) {
10341103 if b .Debug () {
1035- pos := b .ir . Program .Fset .Position (instr .Pos ())
1104+ pos := b .program .Fset .Position (instr .Pos ())
10361105 b .SetCurrentDebugLocation (uint (pos .Line ), uint (pos .Column ), b .difunc , llvm.Metadata {})
10371106 }
10381107
0 commit comments