func (c *compiler) createFunctionMetadata(f *ast.FuncDecl, fn *LLVMValue) llvm.DebugDescriptor { if len(c.debug_context) == 0 { return nil } file := c.fileset.File(f.Pos()) fnptr := fn.value fun := fnptr.IsAFunction() if fun.IsNil() { fnptr = llvm.ConstExtractValue(fn.value, []uint32{0}) } meta := &llvm.SubprogramDescriptor{ Name: fnptr.Name(), DisplayName: f.Name.Name, Path: llvm.FileDescriptor(file.Name()), Line: uint32(file.Line(f.Pos())), ScopeLine: uint32(file.Line(f.Body.Pos())), Context: &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())}, Function: fnptr} var result types.Type var metaparams []llvm.DebugDescriptor if ftyp, ok := fn.Type().(*types.Signature); ok { if recv := ftyp.Recv(); recv != nil { metaparams = append(metaparams, c.tollvmDebugDescriptor(recv.Type())) } if ftyp.Params() != nil { for i := 0; i < ftyp.Params().Len(); i++ { p := ftyp.Params().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } if ftyp.Results() != nil { result = ftyp.Results().At(0).Type() // TODO: what to do with multiple returns? for i := 1; i < ftyp.Results().Len(); i++ { p := ftyp.Results().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } } meta.Type = llvm.NewSubroutineCompositeType( c.tollvmDebugDescriptor(result), metaparams, ) // compile unit is the first context object pushed compileUnit := c.debug_context[0].(*llvm.CompileUnitDescriptor) compileUnit.Subprograms = append(compileUnit.Subprograms, meta) return meta }
func (c *compiler) createBlockMetadata(stmt *ast.BlockStmt) llvm.DebugDescriptor { uniqueId++ file := c.fileset.File(stmt.Pos()) fd := llvm.FileDescriptor(file.Name()) return &llvm.BlockDescriptor{ File: &fd, Line: uint32(file.Line(stmt.Pos())), Context: c.currentDebugContext(), Id: uniqueId, } }
func (c *compiler) newStackVarEx(argument int, stackf *LLVMValue, v types.Object, value llvm.Value, name string) (stackvalue llvm.Value, stackvar *LLVMValue) { typ := v.Type() // We need to put alloca instructions in the top block or the values // displayed when inspecting these variables in a debugger will be // completely messed up. curBlock := c.builder.GetInsertBlock() if p := curBlock.Parent(); !p.IsNil() { fb := p.FirstBasicBlock() fi := fb.FirstInstruction() if !fb.IsNil() && !fi.IsNil() { c.builder.SetInsertPointBefore(fi) } } old := c.builder.CurrentDebugLocation() c.builder.SetCurrentDebugLocation(llvm.Value{}) stackvalue = c.builder.CreateAlloca(c.types.ToLLVM(typ), name) // For arguments we want to insert the store instruction // without debug information to ensure that they are executed // (and hence have proper values) before the debugger hits the // first line in a function. if argument == 0 { c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) } if !value.IsNil() { c.builder.CreateStore(value, stackvalue) } c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ)) stackvar = ptrvalue.makePointee() stackvar.stack = stackf c.objectdata[v].Value = stackvar file := c.fileset.File(v.Pos()) tag := llvm.DW_TAG_auto_variable if argument > 0 { tag = llvm.DW_TAG_arg_variable } ld := llvm.NewLocalVariableDescriptor(tag) ld.Argument = uint32(argument) ld.Line = uint32(file.Line(v.Pos())) ld.Name = name ld.File = &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())} ld.Type = c.tollvmDebugDescriptor(typ) ld.Context = c.currentDebugContext() c.builder.InsertDeclare(c.module.Module, llvm.MDNode([]llvm.Value{stackvalue}), c.debug_info.MDNode(ld)) return stackvalue, stackvar }
// createLocalVariableMetadata creates and returns a debug descriptor for // a local variable in a function. // // obj is the go/types object for the var. // paramIndex is 0 for "auto" variables (non-parameter stack vars), and a // 1-based index for parameter vars. func (c *compiler) createLocalVariableMetadata(obj types.Object, paramIndex int) llvm.DebugDescriptor { ctx := c.currentDebugContext() if ctx == nil { return nil } tag := llvm.DW_TAG_auto_variable if paramIndex > 0 { tag = llvm.DW_TAG_arg_variable } position := c.fileset.Position(obj.Pos()) ld := llvm.NewLocalVariableDescriptor(tag) ld.Argument = uint32(paramIndex) ld.Line = uint32(position.Line) ld.Name = obj.Name() ld.File = &llvm.ContextDescriptor{llvm.FileDescriptor(position.Filename)} ld.Type = c.tollvmDebugDescriptor(obj.Type()) ld.Context = ctx return ld }
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.initfuncs = nil compiler.varinitfuncs = nil // If no import path is specified, or the package's // name (not path) is "main", then set the import // path to be the same as the package's name. if importpath == "" || files[0].Name.String() == "main" { importpath = files[0].Name.String() } // Type-check, and store object data. compiler.typeinfo.Types = make(map[ast.Expr]types.Type) compiler.typeinfo.Values = make(map[ast.Expr]exact.Value) compiler.typeinfo.Objects = make(map[*ast.Ident]types.Object) compiler.typeinfo.Implicits = make(map[ast.Node]types.Object) compiler.typeinfo.Selections = make(map[*ast.SelectorExpr]*types.Selection) compiler.objectdata = make(map[types.Object]*ObjectData) compiler.methodsets = make(map[types.Type]*methodset) compiler.exportedtypes = nil compiler.llvmtypes = NewLLVMTypeMap(compiler.target) pkg, err := compiler.typecheck(importpath, fset, files) if err != nil { return nil, err } compiler.pkg = pkg // Create a Module, which contains the LLVM bitcode. Dispose it on panic, // otherwise we'll set a finalizer at the end. The caller may invoke // Dispose manually, which will render the finalizer a no-op. modulename := importpath compiler.module = &Module{llvm.NewModule(modulename), modulename, false} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.target.String()) defer func() { if e := recover(); e != nil { compiler.module.Dispose() panic(e) } }() // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. var resolver Resolver = compiler compiler.FunctionCache = NewFunctionCache(compiler) compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, compiler.FunctionCache, resolver) // Create a Builder, for building LLVM instructions. compiler.builder = newBuilder(compiler.types) defer compiler.builder.Dispose() compiler.debug_info = &llvm.DebugInfo{} // Compile each file in the package. for _, file := range files { compiler.compile_unit = &llvm.CompileUnitDescriptor{ Language: llvm.DW_LANG_Go, Path: llvm.FileDescriptor(fset.File(file.Pos()).Name()), Producer: LLGOProducer, Runtime: LLGORuntimeVersion, } compiler.pushDebugContext(&compiler.compile_unit.Path) for _, decl := range file.Decls { compiler.VisitDecl(decl) } compiler.popDebugContext() if len(compiler.debug_context) > 0 { log.Panicln(compiler.debug_context) } compiler.module.AddNamedMetadataOperand("llvm.dbg.cu", compiler.debug_info.MDNode(compiler.compile_unit)) } // Export runtime type information. compiler.exportRuntimeTypes() // Wrap "main.main" in a call to runtime.main. if importpath == "main" { err = compiler.createMainFunction() if err != nil { return nil, err } } else { var e = exporter{compiler: compiler} if err := e.Export(pkg); err != nil { return nil, err } } // Create global constructors. The initfuncs/varinitfuncs // slices are in the order of visitation; we generate the // list of constructors in the reverse order. // // The llgo linker will link modules in the order of // package dependency, i.e. if A requires B, then llgo-link // will link the modules in the order A, B. The "runtime" // package is always last. // // At program initialisation, the runtime initialisation // function (runtime.main) will invoke the constructors // in reverse order. var initfuncs [][]llvm.Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { ctortype := llvm.PointerType(llvm.Int8Type(), 0) var ctors []llvm.Value var index int = 0 for _, initfuncs := range initfuncs { for _, fnptr := range initfuncs { name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index) fnptr.SetName(name) fnptr = llvm.ConstBitCast(fnptr, ctortype) ctors = append(ctors, fnptr) index++ } } for i, n := 0, len(ctors); i < n/2; i++ { ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i] } ctorsInit := llvm.ConstArray(ctortype, ctors) ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors") ctorsVar.SetInitializer(ctorsInit) ctorsVar.SetLinkage(llvm.AppendingLinkage) } // Create debug metadata. //compiler.createMetadata() return compiler.module, nil }