Skip to content
This repository has been archived by the owner on Dec 14, 2023. It is now read-only.

Commit

Permalink
Merge pull request #78 from quarnster/debug
Browse files Browse the repository at this point in the history
llgo: Emit more debug metadata. For issue #49.
  • Loading branch information
axw committed Oct 1, 2013
2 parents 6a2b2b0 + fa5f193 commit 2b8d1a1
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 32 deletions.
18 changes: 17 additions & 1 deletion cmd/llgo-build/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
)

// linkdeps links dependencies into the specified output file.
Expand Down Expand Up @@ -68,8 +69,23 @@ func linkdeps(pkg *build.Package, output string) error {

// Finally, link with clang++ to get exception handling.
if !emitllvm || triple == "pnacl" {
input := output
if strings.Contains(triple, "darwin") || strings.Contains(triple, "mac") {
// Not doing this intermediate step will make it invoke "dsymutil"
// which then asserts and kills the build.
// See discussion in issue #49 for more details.
input += ".o"
args := []string{"-g", "-c", "-o", input, output}
cmd := exec.Command(clang, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = runCmd(cmd); err != nil {
return err
}
}

clangxx := clang + "++"
args := []string{"-pthread", "-o", output, output}
args := []string{"-pthread", "-g", "-o", output, input}
if triple == "pnacl" {
args = append(args, "-l", "ppapi")
}
Expand Down
19 changes: 19 additions & 0 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ type compiler struct {
// field will have been updated to the true triple used to
// compile PNaCl modules.
pnacl bool

debug_context []llvm.DebugDescriptor
compile_unit *llvm.CompileUnitDescriptor
debug_info *llvm.DebugInfo
}

func (c *compiler) archinfo() (intsize, ptrsize int64) {
Expand Down Expand Up @@ -285,11 +289,25 @@ func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, import
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.
Expand Down Expand Up @@ -386,6 +404,7 @@ func (c *compiler) createMainFunction() error {
// function with no result.
runtimeMain := c.NamedFunction("runtime.main", "func(int32, **byte, **byte, *int8) int32")
main := c.NamedFunction("main", "func(int32, **byte, **byte) int32")
c.builder.SetCurrentDebugLocation(c.debug_info.MDNode(nil))
entry := llvm.AddBasicBlock(main, "entry")
c.builder.SetInsertPointAtEnd(entry)
mainMain = c.builder.CreateBitCast(mainMain, runtimeMain.Type().ElementType().ParamTypes()[3], "")
Expand Down
112 changes: 112 additions & 0 deletions debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package llgo

import (
"code.google.com/p/go.tools/go/types"
"github.com/axw/gollvm/llvm"
"go/ast"
"go/token"
)

// llgo constants.
Expand All @@ -23,8 +25,61 @@ var (
Alignment: 32,
TypeEncoding: llvm.DW_ATE_signed,
}
void_debug_type = &llvm.BasicTypeDescriptor{
Name: "void",
Size: 0,
Alignment: 0,
}
)

func (c *compiler) tollvmDebugDescriptor(t types.Type) llvm.DebugDescriptor {
switch t := t.(type) {
case *types.Pointer:
return llvm.NewPointerDerivedType(c.tollvmDebugDescriptor(t.Elem()))
case nil:
return void_debug_type
}
bt := &llvm.BasicTypeDescriptor{
Name: c.types.TypeString(t),
Size: uint64(c.types.Sizeof(t) * 8),
Alignment: uint64(c.types.Alignof(t) * 8),
}
if basic, ok := t.(*types.Basic); ok {
switch bi := basic.Info(); {
case bi&types.IsBoolean != 0:
bt.TypeEncoding = llvm.DW_ATE_boolean
case bi&types.IsUnsigned != 0:
bt.TypeEncoding = llvm.DW_ATE_unsigned
case bi&types.IsInteger != 0:
bt.TypeEncoding = llvm.DW_ATE_signed
case bi&types.IsFloat != 0:
bt.TypeEncoding = llvm.DW_ATE_float
}
}
return bt
}

func (c *compiler) pushDebugContext(d llvm.DebugDescriptor) {
c.debug_context = append(c.debug_context, d)
}

func (c *compiler) popDebugContext() {
c.debug_context = c.debug_context[:len(c.debug_context)-1]
}

func (c *compiler) currentDebugContext() llvm.DebugDescriptor {
return c.debug_context[len(c.debug_context)-1]
}

func (c *compiler) setDebugLine(pos token.Pos) {
file := c.fileset.File(pos)
ld := &llvm.LineDescriptor{
Line: uint32(file.Line(pos)),
Context: c.currentDebugContext(),
}
c.builder.SetCurrentDebugLocation(c.debug_info.MDNode(ld))
}

// Debug intrinsic collectors.
func createGlobalVariableMetadata(global llvm.Value) llvm.DebugDescriptor {
return &llvm.GlobalVariableDescriptor{
Expand All @@ -36,6 +91,63 @@ func createGlobalVariableMetadata(global llvm.Value) llvm.DebugDescriptor {
Value: global}
}

var uniqueId uint32

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) createFunctionMetadata(f *ast.FuncDecl, fn *LLVMValue) llvm.DebugDescriptor {
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)
c.compile_unit.Subprograms = append(c.compile_unit.Subprograms, meta)
return meta
}

func (c *compiler) createMetadata() {
functions := []llvm.DebugDescriptor{}
globals := []llvm.DebugDescriptor{}
Expand Down
23 changes: 10 additions & 13 deletions decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,7 @@ func (c *compiler) buildFunction(f *LLVMValue, context, params, results *types.T
name := v.Name()
if !isBlank(name) {
value := llvm_fn.Param(i + paramoffset)
typ := v.Type()
stackvalue := c.builder.CreateAlloca(c.types.ToLLVM(typ), name)
c.builder.CreateStore(value, stackvalue)
ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ))
stackvar := ptrvalue.makePointee()
stackvar.stack = f
c.objectdata[v].Value = stackvar
c.newArgStackVar(i+1, f, v, value, name)
}
}

Expand All @@ -168,12 +162,7 @@ func (c *compiler) buildFunction(f *LLVMValue, context, params, results *types.T
if allocstack {
typ := v.Type()
llvmtyp := c.types.ToLLVM(typ)
stackptr := c.builder.CreateAlloca(llvmtyp, name)
c.builder.CreateStore(llvm.ConstNull(llvmtyp), stackptr)
ptrvalue := c.NewValue(stackptr, types.NewPointer(typ))
stackvar := ptrvalue.makePointee()
stackvar.stack = f
c.objectdata[v].Value = stackvar
c.newStackVar(f, v, llvm.ConstNull(llvmtyp), name)
}
}

Expand All @@ -184,6 +173,8 @@ func (c *compiler) buildFunction(f *LLVMValue, context, params, results *types.T
c.VisitBlockStmt(body, false)
c.functions.pop()

c.setDebugLine(body.End())

// If the last instruction in the function is not a terminator, then
// we either have unreachable code or a missing optional return statement
// (the latter case is allowable only for functions without results).
Expand Down Expand Up @@ -226,6 +217,11 @@ func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value {
paramVars = append(paramVars, p)
}
}

c.pushDebugContext(c.createFunctionMetadata(f, fn))
defer c.popDebugContext()
c.setDebugLine(f.Pos())

paramVarsTuple := types.NewTuple(paramVars...)
c.buildFunction(fn, nil, paramVarsTuple, ftyp.Results(), f.Body)

Expand Down Expand Up @@ -429,6 +425,7 @@ func (c *compiler) VisitGenDecl(decl *ast.GenDecl) {
}

func (c *compiler) VisitDecl(decl ast.Decl) Value {
c.setDebugLine(decl.Pos())
// This is temporary. We'll return errors later, rather than panicking.
if c.Logger != nil {
c.Logger.Println("Compile declaration:", c.fileset.Position(decl.Pos()))
Expand Down
1 change: 1 addition & 0 deletions expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ func (c *compiler) VisitTypeAssertExpr(expr *ast.TypeAssertExpr) Value {
}

func (c *compiler) VisitExpr(expr ast.Expr) Value {
c.setDebugLine(expr.Pos())
// Before all else, check if we've got a constant expression.
// go/types performs constant folding, and we store the value
// alongside the expression's type.
Expand Down
8 changes: 7 additions & 1 deletion llgo/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,13 @@ func runMainFunction(m *llgo.Module) (output []string, err error) {
}

exepath := filepath.Join(tempdir, "test")
cmd = exec.Command("clang++", "-pthread", "-g", "-o", exepath, bcpath)
args := []string{"-pthread", "-o", exepath, bcpath}
if runtime.GOOS != "darwin" {
// TODO(q): -g breaks badly on my system at the moment, so is not enabled on darwin for now
args = append([]string{"-g"}, args...)
}

cmd = exec.Command("clang++", args...)
data, err = cmd.CombinedOutput()
if err != nil {
output = strings.Split(strings.TrimSpace(string(data)), "\n")
Expand Down
25 changes: 8 additions & 17 deletions stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func (c *compiler) VisitIncDecStmt(stmt *ast.IncDecStmt) {
}

func (c *compiler) VisitBlockStmt(stmt *ast.BlockStmt, createNewBlock bool) {
c.pushDebugContext(c.createBlockMetadata(stmt))
defer c.popDebugContext()
c.setDebugLine(stmt.Pos())

// This is a little awkward, but it makes dealing with branching easier.
// A free-standing block statement (i.e. one not attached to a control
// statement) will splice in a new block.
Expand Down Expand Up @@ -289,13 +293,7 @@ func (c *compiler) assignees(stmt *ast.AssignStmt) []*LLVMValue {
}
obj := c.typeinfo.Objects[x]
if stmt.Tok == token.DEFINE {
typ := obj.Type()
llvmtyp := c.types.ToLLVM(typ)
ptr := c.builder.CreateAlloca(llvmtyp, x.Name)
ptrtyp := types.NewPointer(typ)
stackvar := c.NewValue(ptr, ptrtyp).makePointee()
stackvar.stack = c.functions.top().LLVMValue
c.objectdata[obj].Value = stackvar
_, stackvar := c.newStackVar(c.functions.top().LLVMValue, obj, llvm.Value{}, x.Name)
lhs[i] = stackvar
continue
}
Expand Down Expand Up @@ -564,20 +562,12 @@ func (c *compiler) VisitRangeStmt(stmt *ast.RangeStmt) {
if stmt.Tok == token.DEFINE {
if key := stmt.Key.(*ast.Ident); !isBlank(key.Name) {
keyobj := c.typeinfo.Objects[key]
keyType := keyobj.Type()
keyPtr = c.builder.CreateAlloca(c.types.ToLLVM(keyType), "")
stackvar := c.NewValue(keyPtr, types.NewPointer(keyType)).makePointee()
stackvar.stack = c.functions.top().LLVMValue
c.objectdata[keyobj].Value = stackvar
keyPtr, _ = c.newStackVar(c.functions.top().LLVMValue, keyobj, llvm.Value{}, key.Name)
}
if stmt.Value != nil {
if value := stmt.Value.(*ast.Ident); !isBlank(value.Name) {
valueobj := c.typeinfo.Objects[value]
valueType := valueobj.Type()
valuePtr = c.builder.CreateAlloca(c.types.ToLLVM(valueType), "")
stackvar := c.NewValue(valuePtr, types.NewPointer(valueType)).makePointee()
stackvar.stack = c.functions.top().LLVMValue
c.objectdata[valueobj].Value = stackvar
valuePtr, _ = c.newStackVar(c.functions.top().LLVMValue, valueobj, llvm.Value{}, value.Name)
}
}
} else {
Expand Down Expand Up @@ -908,6 +898,7 @@ func (c *compiler) VisitTypeSwitchStmt(stmt *ast.TypeSwitchStmt) {
}

func (c *compiler) VisitStmt(stmt ast.Stmt) {
c.setDebugLine(stmt.Pos())
if c.Logger != nil {
c.Logger.Println("Compile statement:", reflect.TypeOf(stmt),
"@", c.fileset.Position(stmt.Pos()))
Expand Down
Loading

0 comments on commit 2b8d1a1

Please sign in to comment.