irgen: make it possible to use a custom importer

Differential Revision: http://reviews.llvm.org/D6803

llvm-svn: 225029
GitOrigin-RevId: a0a53085e1909c18af8e77c4eb02d8448c7314ca
diff --git a/irgen/compiler.go b/irgen/compiler.go
index c7768e2..60bd62f 100644
--- a/irgen/compiler.go
+++ b/irgen/compiler.go
@@ -15,7 +15,6 @@
 
 import (
 	"bytes"
-	"fmt"
 	"go/ast"
 	"go/token"
 	"log"
@@ -82,6 +81,15 @@
 	// SanitizerAttribute is an attribute to apply to functions to enable
 	// dynamic instrumentation using a sanitizer.
 	SanitizerAttribute llvm.Attribute
+
+	// Importer is the importer. If nil, the compiler will set this field
+	// automatically using MakeImporter().
+	Importer types.Importer
+
+	// InitMap is the init map used by Importer. If Importer is nil, the
+	// compiler will set this field automatically using MakeImporter().
+	// If Importer is non-nil, InitMap must be non-nil also.
+	InitMap map[*types.Package]gccgoimporter.InitData
 }
 
 type Compiler struct {
@@ -151,30 +159,44 @@
 	}
 }
 
+// MakeImporter sets CompilerOptions.Importer to an appropriate importer
+// for the search paths given in CompilerOptions.ImportPaths, and sets
+// CompilerOptions.InitMap to an init map belonging to that importer.
+// If CompilerOptions.GccgoPath is non-empty, the importer will also use
+// the search paths for that gccgo installation.
+func (opts *CompilerOptions) MakeImporter() error {
+	opts.InitMap = make(map[*types.Package]gccgoimporter.InitData)
+	if opts.GccgoPath == "" {
+		paths := append(append([]string{}, opts.ImportPaths...), ".")
+		opts.Importer = gccgoimporter.GetImporter(paths, opts.InitMap)
+	} else {
+		var inst gccgoimporter.GccgoInstallation
+		err := inst.InitFromDriver(opts.GccgoPath)
+		if err != nil {
+			return err
+		}
+		opts.Importer = inst.GetImporter(opts.ImportPaths, opts.InitMap)
+	}
+	return nil
+}
+
 func (compiler *compiler) compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
 	buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
 	if err != nil {
 		return nil, err
 	}
 
-	initmap := make(map[*types.Package]gccgoimporter.InitData)
-	var importer types.Importer
-	if compiler.GccgoPath == "" {
-		paths := append(append([]string{}, compiler.ImportPaths...), ".")
-		importer = gccgoimporter.GetImporter(paths, initmap)
-	} else {
-		var inst gccgoimporter.GccgoInstallation
-		err = inst.InitFromDriver(compiler.GccgoPath)
+	if compiler.Importer == nil {
+		err = compiler.MakeImporter()
 		if err != nil {
 			return nil, err
 		}
-		importer = inst.GetImporter(compiler.ImportPaths, initmap)
 	}
 
 	impcfg := &loader.Config{
 		Fset: fset,
 		TypeChecker: types.Config{
-			Import: importer,
+			Import: compiler.Importer,
 			Sizes:  compiler.llvmtypes,
 		},
 		Build: &buildctx.Context,
@@ -235,11 +257,9 @@
 	compiler.processAnnotations(unit, mainPkginfo)
 
 	if importpath == "main" {
-		if err = compiler.createInitMainFunction(mainPkg, initmap); err != nil {
-			return nil, fmt.Errorf("failed to create __go_init_main: %v", err)
-		}
+		compiler.createInitMainFunction(mainPkg)
 	} else {
-		compiler.module.ExportData = compiler.buildExportData(mainPkg, initmap)
+		compiler.module.ExportData = compiler.buildExportData(mainPkg)
 	}
 
 	return compiler.module, nil
@@ -262,10 +282,10 @@
 	}
 }
 
-func (c *compiler) buildPackageInitData(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) gccgoimporter.InitData {
+func (c *compiler) buildPackageInitData(mainPkg *ssa.Package) gccgoimporter.InitData {
 	var inits []gccgoimporter.PackageInit
 	for _, imp := range mainPkg.Object.Imports() {
-		inits = append(inits, initmap[imp].Inits...)
+		inits = append(inits, c.InitMap[imp].Inits...)
 	}
 	sort.Sort(byPriorityThenFunc(inits))
 
@@ -301,8 +321,8 @@
 	return gccgoimporter.InitData{ourprio, uniqinits}
 }
 
-func (c *compiler) createInitMainFunction(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) error {
-	initdata := c.buildPackageInitData(mainPkg, initmap)
+func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
+	initdata := c.buildPackageInitData(mainPkg)
 
 	ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
 	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
@@ -322,14 +342,13 @@
 	}
 
 	builder.CreateRetVoid()
-	return nil
 }
 
-func (c *compiler) buildExportData(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) []byte {
+func (c *compiler) buildExportData(mainPkg *ssa.Package) []byte {
 	exportData := importer.ExportData(mainPkg.Object)
 	b := bytes.NewBuffer(exportData)
 
-	initdata := c.buildPackageInitData(mainPkg, initmap)
+	initdata := c.buildPackageInitData(mainPkg)
 	b.WriteString("v1;\npriority ")
 	b.WriteString(strconv.Itoa(initdata.Priority))
 	b.WriteString(";\n")