diff --git a/builder/build.go b/builder/build.go index a598f01965..063a0c289f 100644 --- a/builder/build.go +++ b/builder/build.go @@ -14,6 +14,7 @@ import ( "fmt" "go/types" "hash/crc32" + "log" "math/bits" "os" "os/exec" @@ -568,11 +569,42 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe defer irbuilder.Dispose() irbuilder.SetInsertPointAtEnd(block) ptrType := llvm.PointerType(mod.Context().Int8Type(), 0) + + targetData := llvm.NewTargetData(mod.DataLayout()) + uintptrType := mod.Context().IntType(targetData.PointerSize() * 8) + int32Type := mod.Context().Int32Type() + + printstrFn := mod.NamedFunction("runtime.printstring") + + if config.PrintInit() { + log.Println("creating runtime.initAll") + } + for _, pkg := range lprogram.Sorted() { - pkgInit := mod.NamedFunction(pkg.Pkg.Path() + ".init") + pkgpathName := pkg.Pkg.Path() + ".init" + pkgInit := mod.NamedFunction(pkgpathName) if pkgInit.IsNil() { panic("init not found for " + pkg.Pkg.Path()) } + + if config.PrintInit() { + log.Println("\t", pkgpathName) + + pkgpathLen := llvm.ConstInt(uintptrType, uint64(len(pkgpathName+"\n")), false) + pkgpathInitializer := mod.Context().ConstString(pkgpathName+"\n", false) + pkgpathGlobal := llvm.AddGlobal(mod, pkgpathInitializer.Type(), pkgpathName) + pkgpathGlobal.SetInitializer(pkgpathInitializer) + pkgpathGlobal.SetAlignment(1) + pkgpathGlobal.SetUnnamedAddr(true) + pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage) + pkgpathGlobal.SetGlobalConstant(true) + pkgpathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{ + llvm.ConstInt(int32Type, 0, false), + llvm.ConstInt(int32Type, 0, false), + }) + + irbuilder.CreateCall(printstrFn.GlobalValueType(), printstrFn, []llvm.Value{pkgpathPtr, pkgpathLen, llvm.Undef(ptrType)}, "") + } irbuilder.CreateCall(pkgInit.GlobalValueType(), pkgInit, []llvm.Value{llvm.Undef(ptrType)}, "") } irbuilder.CreateRetVoid() diff --git a/compileopts/config.go b/compileopts/config.go index 7ce7ae5470..dd3c97c1b1 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -478,6 +478,11 @@ func (c *Config) DumpSSA() bool { return c.Options.DumpSSA } +// PrintInit returns whether to debug init function creation +func (c *Config) PrintInit() bool { + return c.Options.PrintInit +} + // VerifyIR returns whether to run extra checks on the IR. This is normally // disabled but enabled during testing. func (c *Config) VerifyIR() bool { diff --git a/compileopts/options.go b/compileopts/options.go index e543dca459..c1a8e2fe02 100644 --- a/compileopts/options.go +++ b/compileopts/options.go @@ -47,6 +47,7 @@ type Options struct { PrintSizes string PrintAllocs *regexp.Regexp // regexp string PrintStacks bool + PrintInit bool Tags []string GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value TestConfig TestConfig diff --git a/interp/interp.go b/interp/interp.go index 30b0872485..1b096177d6 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -110,6 +110,10 @@ func Run(mod llvm.Module, timeout time.Duration, debug bool) error { // finished, the call to the package initializer can be removed. for _, call := range initCalls { initName := call.CalledValue().Name() + if strings.HasSuffix(initName, "runtime.printstring") { + continue + + } if !strings.HasSuffix(initName, ".init") { return errorAt(call, "interp: expected all instructions in "+initAll.Name()+" to be *.init() calls") } diff --git a/main.go b/main.go index e2736fd17b..a6bc59d835 100644 --- a/main.go +++ b/main.go @@ -1639,6 +1639,7 @@ func main() { // Internal flags, that are only intended for TinyGo development. printIR := flag.Bool("internal-printir", false, "print LLVM IR") + printInit := flag.Bool("internal-printinit", false, "print init() functions") dumpSSA := flag.Bool("internal-dumpssa", false, "dump internal Go SSA") verifyIR := flag.Bool("internal-verifyir", false, "run extra verification steps on LLVM IR") // Don't generate debug information in the IR, to make IR more readable. @@ -1748,6 +1749,7 @@ func main() { PrintSizes: *printSize, PrintStacks: *printStacks, PrintAllocs: printAllocs, + PrintInit: *printInit, Tags: []string(tags), TestConfig: testConfig, GlobalValues: globalVarValues,