blob: acb922ee5a4f03850c87c89c657d4d2999074a6e [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:42 +00001//===- compiler.go - IR generator entry point -----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the main IR generator entry point, (*Compiler).Compile.
11//
12//===----------------------------------------------------------------------===//
13
14package irgen
15
16import (
17 "bytes"
Peter Collingbourne93509422014-12-31 00:25:32 +000018 "go/ast"
Peter Collingbournead9841e2014-11-27 00:06:42 +000019 "go/token"
20 "log"
21 "sort"
22 "strconv"
Peter Collingbournead9841e2014-11-27 00:06:42 +000023
24 llgobuild "llvm.org/llgo/build"
25 "llvm.org/llgo/debug"
26 "llvm.org/llvm/bindings/go/llvm"
27
Peter Collingbourne56109b72015-01-13 20:45:08 +000028 "llvm.org/llgo/third_party/gotools/go/gccgoimporter"
29 "llvm.org/llgo/third_party/gotools/go/importer"
30 "llvm.org/llgo/third_party/gotools/go/loader"
31 "llvm.org/llgo/third_party/gotools/go/ssa"
32 "llvm.org/llgo/third_party/gotools/go/types"
Peter Collingbournead9841e2014-11-27 00:06:42 +000033)
34
35type Module struct {
36 llvm.Module
37 Path string
38 ExportData []byte
Peter Collingbourne76c1d4e2014-12-31 00:25:35 +000039 Package *types.Package
Peter Collingbournead9841e2014-11-27 00:06:42 +000040 disposed bool
41}
42
43func (m *Module) Dispose() {
44 if m.disposed {
45 return
46 }
47 m.Module.Dispose()
48 m.disposed = true
49}
50
51///////////////////////////////////////////////////////////////////////////////
52
53type CompilerOptions struct {
54 // TargetTriple is the LLVM triple for the target.
55 TargetTriple string
56
57 // GenerateDebug decides whether debug data is
58 // generated in the output module.
59 GenerateDebug bool
60
61 // DebugPrefixMaps is a list of mappings from source prefixes to
62 // replacement prefixes, to be applied in debug info.
63 DebugPrefixMaps []debug.PrefixMap
64
65 // Logger is a logger used for tracing compilation.
66 Logger *log.Logger
67
68 // DumpSSA is a debugging option that dumps each SSA function
69 // to stderr before generating code for it.
70 DumpSSA bool
71
72 // GccgoPath is the path to the gccgo binary whose libgo we read import
73 // data from. If blank, the caller is expected to supply an import
74 // path in ImportPaths.
75 GccgoPath string
76
Peter Collingbourned34d92f2014-12-31 00:25:39 +000077 // Whether to use the gccgo ABI.
78 GccgoABI bool
79
Peter Collingbournead9841e2014-11-27 00:06:42 +000080 // ImportPaths is the list of additional import paths
81 ImportPaths []string
82
83 // SanitizerAttribute is an attribute to apply to functions to enable
84 // dynamic instrumentation using a sanitizer.
85 SanitizerAttribute llvm.Attribute
Peter Collingbournea0a53082014-12-31 00:25:36 +000086
87 // Importer is the importer. If nil, the compiler will set this field
88 // automatically using MakeImporter().
89 Importer types.Importer
90
91 // InitMap is the init map used by Importer. If Importer is nil, the
92 // compiler will set this field automatically using MakeImporter().
93 // If Importer is non-nil, InitMap must be non-nil also.
94 InitMap map[*types.Package]gccgoimporter.InitData
Peter Collingbournec253ebc2015-01-14 05:17:41 +000095
96 // PackageCreated is a hook passed to the go/loader package via
97 // loader.Config, see the documentation for that package for more
98 // information.
99 PackageCreated func(*types.Package)
Peter Collingbourne5ab80612015-01-14 05:18:16 +0000100
101 // DisableUnusedImportCheck disables the unused import check performed
102 // by go/types if set to true.
103 DisableUnusedImportCheck bool
Peter Collingbourne38a7dde2015-03-18 08:34:40 +0000104
105 // Packages is used by go/types as the imported package map if non-nil.
106 Packages map[string]*types.Package
Peter Collingbournead9841e2014-11-27 00:06:42 +0000107}
108
109type Compiler struct {
110 opts CompilerOptions
111 dataLayout string
Peter Collingbournead9841e2014-11-27 00:06:42 +0000112}
113
114func NewCompiler(opts CompilerOptions) (*Compiler, error) {
115 compiler := &Compiler{opts: opts}
Peter Collingbournead9841e2014-11-27 00:06:42 +0000116 dataLayout, err := llvmDataLayout(compiler.opts.TargetTriple)
117 if err != nil {
118 return nil, err
119 }
120 compiler.dataLayout = dataLayout
121 return compiler, nil
122}
123
Peter Collingbourne93509422014-12-31 00:25:32 +0000124func (c *Compiler) Compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000125 target := llvm.NewTargetData(c.dataLayout)
126 compiler := &compiler{
127 CompilerOptions: c.opts,
128 dataLayout: c.dataLayout,
129 target: target,
Peter Collingbournead9841e2014-11-27 00:06:42 +0000130 llvmtypes: NewLLVMTypeMap(llvm.GlobalContext(), target),
131 }
Peter Collingbourne93509422014-12-31 00:25:32 +0000132 return compiler.compile(fset, astFiles, importpath)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000133}
134
135type compiler struct {
136 CompilerOptions
137
138 module *Module
139 dataLayout string
140 target llvm.TargetData
141 fileset *token.FileSet
142
143 runtime *runtimeInterface
144 llvmtypes *llvmTypeMap
145 types *TypeMap
146
Peter Collingbournead9841e2014-11-27 00:06:42 +0000147 debug *debug.DIBuilder
148}
149
150func (c *compiler) logf(format string, v ...interface{}) {
151 if c.Logger != nil {
152 c.Logger.Printf(format, v...)
153 }
154}
155
156func (c *compiler) addCommonFunctionAttrs(fn llvm.Value) {
157 fn.AddTargetDependentFunctionAttr("disable-tail-calls", "true")
158 fn.AddTargetDependentFunctionAttr("split-stack", "")
Meador Inge21e53502016-12-06 04:01:11 +0000159 if c.SanitizerAttribute.GetEnumKind() != 0 {
160 fn.AddFunctionAttr(c.SanitizerAttribute)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000161 }
162}
163
Peter Collingbournea0a53082014-12-31 00:25:36 +0000164// MakeImporter sets CompilerOptions.Importer to an appropriate importer
165// for the search paths given in CompilerOptions.ImportPaths, and sets
166// CompilerOptions.InitMap to an init map belonging to that importer.
167// If CompilerOptions.GccgoPath is non-empty, the importer will also use
168// the search paths for that gccgo installation.
169func (opts *CompilerOptions) MakeImporter() error {
170 opts.InitMap = make(map[*types.Package]gccgoimporter.InitData)
171 if opts.GccgoPath == "" {
172 paths := append(append([]string{}, opts.ImportPaths...), ".")
173 opts.Importer = gccgoimporter.GetImporter(paths, opts.InitMap)
174 } else {
175 var inst gccgoimporter.GccgoInstallation
176 err := inst.InitFromDriver(opts.GccgoPath)
177 if err != nil {
178 return err
179 }
180 opts.Importer = inst.GetImporter(opts.ImportPaths, opts.InitMap)
181 }
182 return nil
183}
184
Peter Collingbourne93509422014-12-31 00:25:32 +0000185func (compiler *compiler) compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000186 buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
187 if err != nil {
188 return nil, err
189 }
190
Peter Collingbournea0a53082014-12-31 00:25:36 +0000191 if compiler.Importer == nil {
192 err = compiler.MakeImporter()
Peter Collingbournead9841e2014-11-27 00:06:42 +0000193 if err != nil {
194 return nil, err
195 }
Peter Collingbournead9841e2014-11-27 00:06:42 +0000196 }
197
198 impcfg := &loader.Config{
Peter Collingbourne93509422014-12-31 00:25:32 +0000199 Fset: fset,
Peter Collingbournead9841e2014-11-27 00:06:42 +0000200 TypeChecker: types.Config{
Peter Collingbourne38a7dde2015-03-18 08:34:40 +0000201 Packages: compiler.Packages,
202 Import: compiler.Importer,
203 Sizes: compiler.llvmtypes,
Peter Collingbourne5ab80612015-01-14 05:18:16 +0000204 DisableUnusedImportCheck: compiler.DisableUnusedImportCheck,
Peter Collingbournead9841e2014-11-27 00:06:42 +0000205 },
Peter Collingbourne7d396412015-04-05 23:28:18 +0000206 ImportFromBinary: true,
207 Build: &buildctx.Context,
208 PackageCreated: compiler.PackageCreated,
Peter Collingbournead9841e2014-11-27 00:06:42 +0000209 }
Peter Collingbournead9841e2014-11-27 00:06:42 +0000210 // If no import path is specified, then set the import
211 // path to be the same as the package's name.
212 if importpath == "" {
213 importpath = astFiles[0].Name.String()
214 }
215 impcfg.CreateFromFiles(importpath, astFiles...)
216 iprog, err := impcfg.Load()
217 if err != nil {
218 return nil, err
219 }
220 program := ssa.Create(iprog, ssa.BareInits)
221 mainPkginfo := iprog.InitialPackages()[0]
222 mainPkg := program.CreatePackage(mainPkginfo)
223
224 // Create a Module, which contains the LLVM module.
225 modulename := importpath
Peter Collingbourne76c1d4e2014-12-31 00:25:35 +0000226 compiler.module = &Module{Module: llvm.NewModule(modulename), Path: modulename, Package: mainPkg.Object}
Peter Collingbournead9841e2014-11-27 00:06:42 +0000227 compiler.module.SetTarget(compiler.TargetTriple)
228 compiler.module.SetDataLayout(compiler.dataLayout)
229
230 // Create a new translation unit.
231 unit := newUnit(compiler, mainPkg)
232
233 // Create the runtime interface.
234 compiler.runtime, err = newRuntimeInterface(compiler.module.Module, compiler.llvmtypes)
235 if err != nil {
236 return nil, err
237 }
238
239 mainPkg.Build()
240
241 // Create a struct responsible for mapping static types to LLVM types,
242 // and to runtime/dynamic type values.
243 compiler.types = NewTypeMap(
244 mainPkg,
245 compiler.llvmtypes,
246 compiler.module.Module,
247 compiler.runtime,
248 MethodResolver(unit),
249 )
250
251 if compiler.GenerateDebug {
252 compiler.debug = debug.NewDIBuilder(
253 types.Sizes(compiler.llvmtypes),
254 compiler.module.Module,
255 impcfg.Fset,
256 compiler.DebugPrefixMaps,
257 )
258 defer compiler.debug.Destroy()
259 defer compiler.debug.Finalize()
260 }
261
262 unit.translatePackage(mainPkg)
263 compiler.processAnnotations(unit, mainPkginfo)
264
265 if importpath == "main" {
Peter Collingbournea0a53082014-12-31 00:25:36 +0000266 compiler.createInitMainFunction(mainPkg)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000267 } else {
Peter Collingbournea0a53082014-12-31 00:25:36 +0000268 compiler.module.ExportData = compiler.buildExportData(mainPkg)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000269 }
270
271 return compiler.module, nil
272}
273
274type byPriorityThenFunc []gccgoimporter.PackageInit
275
276func (a byPriorityThenFunc) Len() int { return len(a) }
277func (a byPriorityThenFunc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
278func (a byPriorityThenFunc) Less(i, j int) bool {
279 switch {
280 case a[i].Priority < a[j].Priority:
281 return true
282 case a[i].Priority > a[j].Priority:
283 return false
284 case a[i].InitFunc < a[j].InitFunc:
285 return true
286 default:
287 return false
288 }
289}
290
Peter Collingbournea0a53082014-12-31 00:25:36 +0000291func (c *compiler) buildPackageInitData(mainPkg *ssa.Package) gccgoimporter.InitData {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000292 var inits []gccgoimporter.PackageInit
293 for _, imp := range mainPkg.Object.Imports() {
Peter Collingbournea0a53082014-12-31 00:25:36 +0000294 inits = append(inits, c.InitMap[imp].Inits...)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000295 }
296 sort.Sort(byPriorityThenFunc(inits))
297
298 // Deduplicate init entries. We want to preserve the entry with the highest priority.
299 // Normally a package's priorities will be consistent among its dependencies, but it is
300 // possible for them to be different. For example, if a standard library test augments a
301 // package which is a dependency of 'regexp' (which is imported by every test main package)
302 // with additional dependencies, those dependencies may cause the package under test to
303 // receive a higher priority than indicated by its init clause in 'regexp'.
304 uniqinits := make([]gccgoimporter.PackageInit, len(inits))
305 uniqinitpos := len(inits)
306 uniqinitnames := make(map[string]struct{})
307 for i, _ := range inits {
308 init := inits[len(inits)-1-i]
309 if _, ok := uniqinitnames[init.InitFunc]; !ok {
310 uniqinitnames[init.InitFunc] = struct{}{}
311 uniqinitpos--
312 uniqinits[uniqinitpos] = init
313 }
314 }
315 uniqinits = uniqinits[uniqinitpos:]
316
317 ourprio := 1
318 if len(uniqinits) != 0 {
319 ourprio = uniqinits[len(uniqinits)-1].Priority + 1
320 }
321
322 if imp := mainPkg.Func("init"); imp != nil {
323 impname := c.types.mc.mangleFunctionName(imp)
324 uniqinits = append(uniqinits, gccgoimporter.PackageInit{mainPkg.Object.Name(), impname, ourprio})
325 }
326
327 return gccgoimporter.InitData{ourprio, uniqinits}
328}
329
Peter Collingbournea0a53082014-12-31 00:25:36 +0000330func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
Peter Collingbournecac32592015-04-05 23:31:49 +0000331 int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0)
332 ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000333 initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
334 c.addCommonFunctionAttrs(initMain)
335 entry := llvm.AddBasicBlock(initMain, "entry")
336
337 builder := llvm.GlobalContext().NewBuilder()
338 defer builder.Dispose()
339 builder.SetInsertPointAtEnd(entry)
340
Peter Collingbournecac32592015-04-05 23:31:49 +0000341 args := []llvm.Value{llvm.Undef(int8ptr)}
342
Peter Collingbourned34d92f2014-12-31 00:25:39 +0000343 if !c.GccgoABI {
344 initfn := c.module.Module.NamedFunction("main..import")
345 if !initfn.IsNil() {
Peter Collingbournecac32592015-04-05 23:31:49 +0000346 builder.CreateCall(initfn, args, "")
Peter Collingbourned34d92f2014-12-31 00:25:39 +0000347 }
348 builder.CreateRetVoid()
349 return
350 }
351
352 initdata := c.buildPackageInitData(mainPkg)
353
Peter Collingbournead9841e2014-11-27 00:06:42 +0000354 for _, init := range initdata.Inits {
355 initfn := c.module.Module.NamedFunction(init.InitFunc)
356 if initfn.IsNil() {
357 initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
358 }
Peter Collingbournecac32592015-04-05 23:31:49 +0000359 builder.CreateCall(initfn, args, "")
Peter Collingbournead9841e2014-11-27 00:06:42 +0000360 }
361
362 builder.CreateRetVoid()
Peter Collingbournead9841e2014-11-27 00:06:42 +0000363}
364
Peter Collingbournea0a53082014-12-31 00:25:36 +0000365func (c *compiler) buildExportData(mainPkg *ssa.Package) []byte {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000366 exportData := importer.ExportData(mainPkg.Object)
367 b := bytes.NewBuffer(exportData)
368
Peter Collingbourned34d92f2014-12-31 00:25:39 +0000369 b.WriteString("v1;\n")
370 if !c.GccgoABI {
371 return b.Bytes()
372 }
373
Peter Collingbournea0a53082014-12-31 00:25:36 +0000374 initdata := c.buildPackageInitData(mainPkg)
Peter Collingbourned34d92f2014-12-31 00:25:39 +0000375 b.WriteString("priority ")
Peter Collingbournead9841e2014-11-27 00:06:42 +0000376 b.WriteString(strconv.Itoa(initdata.Priority))
377 b.WriteString(";\n")
378
379 if len(initdata.Inits) != 0 {
380 b.WriteString("init")
381 for _, init := range initdata.Inits {
382 b.WriteRune(' ')
383 b.WriteString(init.Name)
384 b.WriteRune(' ')
385 b.WriteString(init.InitFunc)
386 b.WriteRune(' ')
387 b.WriteString(strconv.Itoa(init.Priority))
388 }
389 b.WriteString(";\n")
390 }
391
392 return b.Bytes()
393}
394
395// vim: set ft=go :