main: remove -no-debug flag

The -no-debug flag controls whether to emit DWARF debug information.
However, instead of limiting debug information altogether, I think it's
better to strip it off at the end if it isn't needed. For several
reasons:

  * Some parts of the compiler now rely on the presence of debug
    information for proper diagnostics.
  * It works better with the cache: there is no distinction between
    debug and no-debug builds.
  * It makes it easier (or possible at all) to enable debug information
    in the wasi-libc library without big downsides.

I'm doing this in a separate commit so this can be reverted if needed.
This commit is contained in:
Ayke van Laethem
2021-07-12 14:25:59 +02:00
parent 2930c44bfc
commit a3ee85890d
9 changed files with 95 additions and 131 deletions
-1
View File
@@ -100,7 +100,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
AutomaticStackSize: config.AutomaticStackSize(), AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize, DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(), NeedsStackObjects: config.NeedsStackObjects(),
Debug: config.EmitDWARF(),
LLVMFeatures: config.LLVMFeatures(), LLVMFeatures: config.LLVMFeatures(),
} }
+2 -9
View File
@@ -209,9 +209,8 @@ func (c *Config) CFlags() []string {
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include")) cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
} }
if c.EmitDWARF() { // Always emit debug information. It is optionally stripped at link time.
cflags = append(cflags, "-g") cflags = append(cflags, "-g")
}
return cflags return cflags
} }
@@ -250,12 +249,6 @@ func (c *Config) VerifyIR() bool {
return c.Options.VerifyIR return c.Options.VerifyIR
} }
// EmitDWARF returns whether to add debug symbols to the IR, for debugging with
// GDB and similar.
func (c *Config) EmitDWARF() bool {
return c.Options.EmitDWARF
}
// Debug returns whether debug (DWARF) information should be retained by the // Debug returns whether debug (DWARF) information should be retained by the
// linker. The default varies by target but can be controlled with the -debug // linker. The default varies by target but can be controlled with the -debug
// command line flag. // command line flag.
-1
View File
@@ -29,7 +29,6 @@ type Options struct {
DumpSSA bool DumpSSA bool
VerifyIR bool VerifyIR bool
PrintCommands func(cmd string, args ...string) PrintCommands func(cmd string, args ...string)
EmitDWARF bool
Debug string Debug string
PrintSizes string PrintSizes string
PrintAllocs *regexp.Regexp // regexp string PrintAllocs *regexp.Regexp // regexp string
+37 -51
View File
@@ -58,7 +58,6 @@ type Config struct {
AutomaticStackSize bool AutomaticStackSize bool
DefaultStackSize uint64 DefaultStackSize uint64
NeedsStackObjects bool NeedsStackObjects bool
Debug bool // Whether to emit debug information in the LLVM module.
LLVMFeatures string LLVMFeatures string
} }
@@ -103,9 +102,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
c.mod = c.ctx.NewModule(moduleName) c.mod = c.ctx.NewModule(moduleName)
c.mod.SetTarget(config.Triple) c.mod.SetTarget(config.Triple)
c.mod.SetDataLayout(c.targetData.String()) c.mod.SetDataLayout(c.targetData.String())
if c.Debug { c.dibuilder = llvm.NewDIBuilder(c.mod)
c.dibuilder = llvm.NewDIBuilder(c.mod)
}
c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8) c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8)
if c.targetData.PointerSize() <= 4 { if c.targetData.PointerSize() <= 4 {
@@ -263,15 +260,13 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
ssaPkg.Build() ssaPkg.Build()
// Initialize debug information. // Initialize debug information.
if c.Debug { c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{ Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?)
Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?) File: "<unknown>",
File: "<unknown>", Dir: "",
Dir: "", Producer: "TinyGo",
Producer: "TinyGo", Optimized: true,
Optimized: true, })
})
}
// Load comments such as //go:extern on globals. // Load comments such as //go:extern on globals.
c.loadASTComments(pkg) c.loadASTComments(pkg)
@@ -286,23 +281,21 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
c.createPackage(irbuilder, ssaPkg) c.createPackage(irbuilder, ssaPkg)
// see: https://reviews.llvm.org/D18355 // see: https://reviews.llvm.org/D18355
if c.Debug { c.mod.AddNamedMetadataOperand("llvm.module.flags",
c.mod.AddNamedMetadataOperand("llvm.module.flags", c.ctx.MDNode([]llvm.Metadata{
c.ctx.MDNode([]llvm.Metadata{ llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch
llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch c.ctx.MDString("Debug Info Version"),
c.ctx.MDString("Debug Info Version"), llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version
llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version }),
}), )
) c.mod.AddNamedMetadataOperand("llvm.module.flags",
c.mod.AddNamedMetadataOperand("llvm.module.flags", c.ctx.MDNode([]llvm.Metadata{
c.ctx.MDNode([]llvm.Metadata{ llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(),
llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), c.ctx.MDString("Dwarf Version"),
c.ctx.MDString("Dwarf Version"), llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(),
llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(), }),
}), )
) c.dibuilder.Finalize()
c.dibuilder.Finalize()
}
return c.mod, c.diagnostics return c.mod, c.diagnostics
} }
@@ -812,20 +805,18 @@ func (b *builder) createFunction() {
b.llvmFn.AddFunctionAttr(noinline) b.llvmFn.AddFunctionAttr(noinline)
} }
// Add debug info, if needed. // Add debug info.
if b.Debug { if b.fn.Synthetic == "package initializer" {
if b.fn.Synthetic == "package initializer" { // Package initializers have no debug info. Create some fake debug
// Package initializers have no debug info. Create some fake debug // info to at least have *something*.
// info to at least have *something*. filename := b.fn.Package().Pkg.Path() + "/<init>"
filename := b.fn.Package().Pkg.Path() + "/<init>" b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0)
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0) } else if b.fn.Syntax() != nil {
} else if b.fn.Syntax() != nil { // Create debug info file if needed.
// Create debug info file if needed. b.difunc = b.attachDebugInfo(b.fn)
b.difunc = b.attachDebugInfo(b.fn)
}
pos := b.program.Fset.Position(b.fn.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
} }
pos := b.program.Fset.Position(b.fn.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
// Pre-create all basic blocks in the function. // Pre-create all basic blocks in the function.
for _, block := range b.fn.DomPreorder() { for _, block := range b.fn.DomPreorder() {
@@ -850,7 +841,7 @@ func (b *builder) createFunction() {
b.locals[param] = b.collapseFormalParam(llvmType, fields) b.locals[param] = b.collapseFormalParam(llvmType, fields)
// Add debug information to this parameter (if available) // Add debug information to this parameter (if available)
if b.Debug && b.fn.Syntax() != nil { if b.fn.Syntax() != nil {
dbgParam := b.getLocalVariable(param.Object().(*types.Var)) dbgParam := b.getLocalVariable(param.Object().(*types.Var))
loc := b.GetCurrentDebugLocation() loc := b.GetCurrentDebugLocation()
if len(fields) == 1 { if len(fields) == 1 {
@@ -910,9 +901,6 @@ func (b *builder) createFunction() {
b.currentBlock = block b.currentBlock = block
for _, instr := range block.Instrs { for _, instr := range block.Instrs {
if instr, ok := instr.(*ssa.DebugRef); ok { if instr, ok := instr.(*ssa.DebugRef); ok {
if !b.Debug {
continue
}
object := instr.Object() object := instr.Object()
variable, ok := object.(*types.Var) variable, ok := object.(*types.Var)
if !ok { if !ok {
@@ -1029,10 +1017,8 @@ func getPos(val posser) token.Pos {
// createInstruction builds the LLVM IR equivalent instructions for the // createInstruction builds the LLVM IR equivalent instructions for the
// particular Go SSA instruction. // particular Go SSA instruction.
func (b *builder) createInstruction(instr ssa.Instruction) { func (b *builder) createInstruction(instr ssa.Instruction) {
if b.Debug { pos := b.program.Fset.Position(getPos(instr))
pos := b.program.Fset.Position(getPos(instr)) b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
switch instr := instr.(type) { switch instr := instr.(type) {
case ssa.Value: case ssa.Value:
+40 -42
View File
@@ -182,27 +182,26 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
entry := c.ctx.AddBasicBlock(wrapper, "entry") entry := c.ctx.AddBasicBlock(wrapper, "entry")
builder.SetInsertPointAtEnd(entry) builder.SetInsertPointAtEnd(entry)
if c.Debug { // Add debug information.
pos := c.program.Fset.Position(pos) pos := c.program.Fset.Position(pos)
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: c.getDIFile(pos.Filename), File: c.getDIFile(pos.Filename),
Parameters: nil, // do not show parameters in debugger Parameters: nil, // do not show parameters in debugger
Flags: 0, // ? Flags: 0, // ?
}) })
difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{
Name: "<goroutine wrapper>", Name: "<goroutine wrapper>",
File: c.getDIFile(pos.Filename), File: c.getDIFile(pos.Filename),
Line: pos.Line, Line: pos.Line,
Type: diFuncType, Type: diFuncType,
LocalToUnit: true, LocalToUnit: true,
IsDefinition: true, IsDefinition: true,
ScopeLine: 0, ScopeLine: 0,
Flags: llvm.FlagPrototyped, Flags: llvm.FlagPrototyped,
Optimized: true, Optimized: true,
}) })
wrapper.SetSubprogram(difunc) wrapper.SetSubprogram(difunc)
builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
}
// Create the list of params for the call. // Create the list of params for the call.
paramTypes := fn.Type().ElementType().ParamTypes() paramTypes := fn.Type().ElementType().ParamTypes()
@@ -246,27 +245,26 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
entry := c.ctx.AddBasicBlock(wrapper, "entry") entry := c.ctx.AddBasicBlock(wrapper, "entry")
builder.SetInsertPointAtEnd(entry) builder.SetInsertPointAtEnd(entry)
if c.Debug { // Add debug information.
pos := c.program.Fset.Position(pos) pos := c.program.Fset.Position(pos)
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: c.getDIFile(pos.Filename), File: c.getDIFile(pos.Filename),
Parameters: nil, // do not show parameters in debugger Parameters: nil, // do not show parameters in debugger
Flags: 0, // ? Flags: 0, // ?
}) })
difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{
Name: "<goroutine wrapper>", Name: "<goroutine wrapper>",
File: c.getDIFile(pos.Filename), File: c.getDIFile(pos.Filename),
Line: pos.Line, Line: pos.Line,
Type: diFuncType, Type: diFuncType,
LocalToUnit: true, LocalToUnit: true,
IsDefinition: true, IsDefinition: true,
ScopeLine: 0, ScopeLine: 0,
Flags: llvm.FlagPrototyped, Flags: llvm.FlagPrototyped,
Optimized: true, Optimized: true,
}) })
wrapper.SetSubprogram(difunc) wrapper.SetSubprogram(difunc)
builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
}
// Get the list of parameters, with the extra parameters at the end. // Get the list of parameters, with the extra parameters at the end.
paramTypes := fn.Type().ElementType().ParamTypes() paramTypes := fn.Type().ElementType().ParamTypes()
+4 -6
View File
@@ -501,12 +501,10 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
} }
defer b.Builder.Dispose() defer b.Builder.Dispose()
// add debug info if needed // add debug info
if c.Debug { pos := c.program.Fset.Position(fn.Pos())
pos := c.program.Fset.Position(fn.Pos()) difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line) b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
}
// set up IR builder // set up IR builder
block := b.ctx.AddBasicBlock(wrapper, "entry") block := b.ctx.AddBasicBlock(wrapper, "entry")
+11 -13
View File
@@ -52,19 +52,17 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
global.SetInitializer(initializer) global.SetInitializer(initializer)
// Add debug info to the interrupt global. // Add debug info to the interrupt global.
if b.Debug { pos := b.program.Fset.Position(instr.Pos())
pos := b.program.Fset.Position(instr.Pos()) diglobal := b.dibuilder.CreateGlobalVariableExpression(b.getDIFile(pos.Filename), llvm.DIGlobalVariableExpression{
diglobal := b.dibuilder.CreateGlobalVariableExpression(b.getDIFile(pos.Filename), llvm.DIGlobalVariableExpression{ Name: "interrupt" + strconv.FormatInt(id.Int64(), 10),
Name: "interrupt" + strconv.FormatInt(id.Int64(), 10), LinkageName: globalName,
LinkageName: globalName, File: b.getDIFile(pos.Filename),
File: b.getDIFile(pos.Filename), Line: pos.Line,
Line: pos.Line, Type: b.getDIType(globalType),
Type: b.getDIType(globalType), Expr: b.dibuilder.CreateExpression(nil),
Expr: b.dibuilder.CreateExpression(nil), LocalToUnit: false,
LocalToUnit: false, })
}) global.AddMetadata(0, diglobal)
global.AddMetadata(0, diglobal)
}
// Create the runtime/interrupt.Interrupt type. It is a struct with a single // Create the runtime/interrupt.Interrupt type. It is a struct with a single
// member of type int. // member of type int.
+1 -1
View File
@@ -386,7 +386,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
llvmGlobal.SetAlignment(alignment) llvmGlobal.SetAlignment(alignment)
} }
if c.Debug && !info.extern { if !info.extern {
// Add debug info. // Add debug info.
pos := c.program.Fset.Position(g.Pos()) pos := c.program.Fset.Position(g.Pos())
diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[pos.Filename], llvm.DIGlobalVariableExpression{ diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[pos.Filename], llvm.DIGlobalVariableExpression{
-7
View File
@@ -1020,7 +1020,6 @@ func main() {
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printCommands := flag.Bool("x", false, "Print commands") printCommands := flag.Bool("x", false, "Print commands")
debug := flag.String("debug", "auto", "remove debug information (auto, true, false)") debug := flag.String("debug", "auto", "remove debug information (auto, true, false)")
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)") ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug") ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)") port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
@@ -1087,7 +1086,6 @@ func main() {
PrintIR: *printIR, PrintIR: *printIR,
DumpSSA: *dumpSSA, DumpSSA: *dumpSSA,
VerifyIR: *verifyIR, VerifyIR: *verifyIR,
EmitDWARF: !*nodebug,
Debug: *debug, Debug: *debug,
PrintSizes: *printSize, PrintSizes: *printSize,
PrintStacks: *printStacks, PrintStacks: *printStacks,
@@ -1175,11 +1173,6 @@ func main() {
err := Flash(pkgName, *port, options) err := Flash(pkgName, *port, options)
handleCompilerError(err) handleCompilerError(err)
} else { } else {
if !options.EmitDWARF {
fmt.Fprintln(os.Stderr, "Debug disabled while running gdb?")
usage()
os.Exit(1)
}
err := FlashGDB(pkgName, *ocdOutput, options) err := FlashGDB(pkgName, *ocdOutput, options)
handleCompilerError(err) handleCompilerError(err)
} }