1
0
mirror of https://github.com/golang/go synced 2024-11-11 20:01:37 -07:00

[dev.regabi] cmd/compile: finish cleanup of Debug parsing

Now that the debug settings are in a struct, use struct tags to set
the usage messages and use reflection to populate debugtab,
much like we did for the Flag struct.

Change-Id: Id2ba30c30a9158c062527715a68bf4dd94679457
Reviewed-on: https://go-review.googlesource.com/c/go/+/272247
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-11-16 01:44:47 -05:00
parent 3c240f5d17
commit eb3086e5a8
3 changed files with 164 additions and 137 deletions

View File

@ -2,149 +2,176 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Debug arguments, set by -d flag.
package gc package gc
import ( import (
"fmt" "fmt"
"log" "log"
"os" "os"
"reflect"
"strconv" "strconv"
"strings" "strings"
"cmd/compile/internal/ssa"
"cmd/internal/objabi" "cmd/internal/objabi"
) )
// Debug arguments. // Debug holds the parsed debugging configuration values.
// These can be specified with the -d flag, as in "-d nil" var Debug = DebugFlags{
// to set the debug_checknil variable. Fieldtrack: &objabi.Fieldtrack_enabled,
// Multiple options can be comma-separated. }
// Each option accepts an optional argument, as in "gcprog=2"
var debugtab = []struct { // DebugFlags defines the debugging configuration values (see var Debug).
// Each struct field is a different value, named for the lower-case of the field name.
// Each field must be an int or string and must have a `help` struct tag.
//
// The -d option takes a comma-separated list of settings.
// Each setting is name=value; for ints, name is short for name=1.
type DebugFlags struct {
Append int `help:"print information about append compilation"`
Checkptr int `help:"instrument unsafe pointer conversions"`
Closure int `help:"print information about closure compilation"`
CompileLater int `help:"compile functions as late as possible"`
DclStack int `help:"run internal dclstack check"`
Defer int `help:"print information about defer compilation"`
DisableNil int `help:"disable nil checks"`
DumpPtrs int `help:"show Node pointers values in dump output"`
DwarfInl int `help:"print information about DWARF inlined function creation"`
Export int `help:"print export data"`
Fieldtrack *int `help:"enable field tracking"`
GCProg int `help:"print dump of GC programs"`
Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"`
LocationLists int `help:"print information about DWARF location list creation"`
Nil int `help:"print information about nil checks"`
PCTab string `help:"print named pc-value table"`
Panic int `help:"show all compiler panics"`
Slice int `help:"print information about slice compilation"`
SoftFloat int `help:"force compiler to emit soft-float code"`
TypeAssert int `help:"print information about type assertion inlining"`
TypecheckInl int `help:"eager typechecking of inline function bodies"`
WB int `help:"print information about write barriers"`
any bool // set when any of the values have been set
}
// Any reports whether any of the debug flags have been set.
func (d *DebugFlags) Any() bool { return d.any }
type debugField struct {
name string name string
help string help string
val interface{} // must be *int or *string val interface{} // *int or *string
}{
{"append", "print information about append compilation", &Debug.Append},
{"checkptr", "instrument unsafe pointer conversions", &Debug.Checkptr},
{"closure", "print information about closure compilation", &Debug.Closure},
{"compilelater", "compile functions as late as possible", &Debug.CompileLater},
{"disablenil", "disable nil checks", &Debug.DisableNil},
{"dclstack", "run internal dclstack check", &Debug.DclStack},
{"dumpptrs", "show Node pointer values in Dump/dumplist output", &Debug.DumpPtrs},
{"gcprog", "print dump of GC programs", &Debug.GCProg},
{"libfuzzer", "coverage instrumentation for libfuzzer", &Debug.Libfuzzer},
{"nil", "print information about nil checks", &Debug.Nil},
{"panic", "do not hide any compiler panic", &Debug.Panic},
{"slice", "print information about slice compilation", &Debug.Slice},
{"typeassert", "print information about type assertion inlining", &Debug.TypeAssert},
{"wb", "print information about write barriers", &Debug.WB},
{"export", "print export data", &Debug.Export},
{"pctab", "print named pc-value table", &Debug.PCTab},
{"locationlists", "print information about DWARF location list creation", &Debug.LocationLists},
{"typecheckinl", "eager typechecking of inline function bodies", &Debug.TypecheckInl},
{"dwarfinl", "print information about DWARF inlined function creation", &Debug.DwarfInl},
{"softfloat", "force compiler to emit soft-float code", &Debug.SoftFloat},
{"defer", "print information about defer compilation", &Debug.Defer},
{"fieldtrack", "enable fieldtracking", &objabi.Fieldtrack_enabled},
} }
var Debug struct { var debugTab []debugField
Append int
Checkptr int func init() {
Closure int v := reflect.ValueOf(&Debug).Elem()
CompileLater int t := v.Type()
DisableNil int for i := 0; i < t.NumField(); i++ {
DclStack int f := t.Field(i)
GCProg int if f.Name == "any" {
Libfuzzer int continue
Nil int }
Panic int name := strings.ToLower(f.Name)
Slice int help := f.Tag.Get("help")
TypeAssert int if help == "" {
WB int panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name))
Export int }
PCTab string ptr := v.Field(i).Addr().Interface()
LocationLists int switch ptr.(type) {
TypecheckInl int default:
DwarfInl int panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
SoftFloat int case *int, *string:
Defer int // ok
DumpPtrs int case **int:
ptr = *ptr.(**int) // record the *int itself
}
debugTab = append(debugTab, debugField{name, help, ptr})
}
} }
func parseDebug() { // DebugSSA is called to set a -d ssa/... option.
// If nil, those options are reported as invalid options.
// If DebugSSA returns a non-empty string, that text is reported as a compiler error.
var DebugSSA func(phase, flag string, val int, valString string) string
// parseDebug parses the -d debug string argument.
func parseDebug(debugstr string) {
// parse -d argument // parse -d argument
if Flag.LowerD != "" { if debugstr == "" {
Split: return
for _, name := range strings.Split(Flag.LowerD, ",") { }
if name == "" { Debug.any = true
Split:
for _, name := range strings.Split(debugstr, ",") {
if name == "" {
continue
}
// display help about the -d option itself and quit
if name == "help" {
fmt.Print(debugHelpHeader)
maxLen := len("ssa/help")
for _, t := range debugTab {
if len(t.name) > maxLen {
maxLen = len(t.name)
}
}
for _, t := range debugTab {
fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
}
// ssa options have their own help
fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
fmt.Print(debugHelpFooter)
os.Exit(0)
}
val, valstring, haveInt := 1, "", true
if i := strings.IndexAny(name, "=:"); i >= 0 {
var err error
name, valstring = name[:i], name[i+1:]
val, err = strconv.Atoi(valstring)
if err != nil {
val, haveInt = 1, false
}
}
for _, t := range debugTab {
if t.name != name {
continue continue
} }
// display help about the -d option itself and quit switch vp := t.val.(type) {
if name == "help" { case nil:
fmt.Print(debugHelpHeader) // Ignore
maxLen := len("ssa/help") case *string:
for _, t := range debugtab { *vp = valstring
if len(t.name) > maxLen { case *int:
maxLen = len(t.name) if !haveInt {
} log.Fatalf("invalid debug value %v", name)
} }
for _, t := range debugtab { *vp = val
fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help) default:
} panic("bad debugtab type")
// ssa options have their own help
fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
fmt.Print(debugHelpFooter)
os.Exit(0)
} }
val, valstring, haveInt := 1, "", true continue Split
if i := strings.IndexAny(name, "=:"); i >= 0 {
var err error
name, valstring = name[:i], name[i+1:]
val, err = strconv.Atoi(valstring)
if err != nil {
val, haveInt = 1, false
}
}
for _, t := range debugtab {
if t.name != name {
continue
}
switch vp := t.val.(type) {
case nil:
// Ignore
case *string:
*vp = valstring
case *int:
if !haveInt {
log.Fatalf("invalid debug value %v", name)
}
*vp = val
default:
panic("bad debugtab type")
}
continue Split
}
// special case for ssa for now
if strings.HasPrefix(name, "ssa/") {
// expect form ssa/phase/flag
// e.g. -d=ssa/generic_cse/time
// _ in phase name also matches space
phase := name[4:]
flag := "debug" // default flag is debug
if i := strings.Index(phase, "/"); i >= 0 {
flag = phase[i+1:]
phase = phase[:i]
}
err := ssa.PhaseOption(phase, flag, val, valstring)
if err != "" {
log.Fatalf(err)
}
continue Split
}
log.Fatalf("unknown debug key -d %s\n", name)
} }
// special case for ssa for now
if DebugSSA != nil && strings.HasPrefix(name, "ssa/") {
// expect form ssa/phase/flag
// e.g. -d=ssa/generic_cse/time
// _ in phase name also matches space
phase := name[4:]
flag := "debug" // default flag is debug
if i := strings.Index(phase, "/"); i >= 0 {
flag = phase[i+1:]
phase = phase[:i]
}
err := DebugSSA(phase, flag, val, valstring)
if err != "" {
log.Fatalf(err)
}
continue Split
}
log.Fatalf("unknown debug key -d %s\n", name)
} }
} }

View File

@ -63,19 +63,19 @@ type CmdFlags struct {
// V is added by objabi.AddVersionFlag // V is added by objabi.AddVersionFlag
W CountFlag "help:\"debug parse tree after type checking\"" W CountFlag "help:\"debug parse tree after type checking\""
LowerC int "help:\"concurrency during compilation (1 means no concurrency)\"" LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
LowerD string "help:\"enable debugging settings; try -d help\"" LowerD func(string) "help:\"enable debugging settings; try -d help\""
LowerE CountFlag "help:\"no limit on number of errors reported\"" LowerE CountFlag "help:\"no limit on number of errors reported\""
LowerH CountFlag "help:\"halt on error\"" LowerH CountFlag "help:\"halt on error\""
LowerJ CountFlag "help:\"debug runtime-initialized variables\"" LowerJ CountFlag "help:\"debug runtime-initialized variables\""
LowerL CountFlag "help:\"disable inlining\"" LowerL CountFlag "help:\"disable inlining\""
LowerM CountFlag "help:\"print optimization decisions\"" LowerM CountFlag "help:\"print optimization decisions\""
LowerO string "help:\"write output to `file`\"" LowerO string "help:\"write output to `file`\""
LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
LowerR CountFlag "help:\"debug generated wrappers\"" LowerR CountFlag "help:\"debug generated wrappers\""
LowerT bool "help:\"enable tracing for debugging the compiler\"" LowerT bool "help:\"enable tracing for debugging the compiler\""
LowerW CountFlag "help:\"debug type checking\"" LowerW CountFlag "help:\"debug type checking\""
LowerV *bool "help:\"increase debug verbosity\"" LowerV *bool "help:\"increase debug verbosity\""
// Special characters // Special characters
Percent int "flag:\"%\" help:\"debug non-static initializers\"" Percent int "flag:\"%\" help:\"debug non-static initializers\""
@ -137,6 +137,7 @@ func ParseFlags() {
Flag.I = addImportDir Flag.I = addImportDir
Flag.LowerC = 1 Flag.LowerC = 1
Flag.LowerD = parseDebug
Flag.LowerP = &Ctxt.Pkgpath Flag.LowerP = &Ctxt.Pkgpath
Flag.LowerV = &Ctxt.Debugvlog Flag.LowerV = &Ctxt.Debugvlog
@ -174,7 +175,7 @@ func ParseFlags() {
Ctxt.Flag_optimize = Flag.N == 0 Ctxt.Flag_optimize = Flag.N == 0
Ctxt.Debugasm = int(Flag.S) Ctxt.Debugasm = int(Flag.S)
if flag.NArg() < 1 && Flag.LowerD != "help" && Flag.LowerD != "ssa/help" { if flag.NArg() < 1 {
usage() usage()
} }
@ -221,8 +222,6 @@ func ParseFlags() {
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args) log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
} }
parseDebug()
if Flag.CompilingRuntime { if Flag.CompilingRuntime {
// Runtime can't use -d=checkptr, at least not yet. // Runtime can't use -d=checkptr, at least not yet.
Debug.Checkptr = 0 Debug.Checkptr = 0
@ -330,7 +329,7 @@ func concurrentBackendAllowed() bool {
// while writing the object file, and that is non-concurrent. // while writing the object file, and that is non-concurrent.
// Adding Debug_vlog, however, causes Debug.S to also print // Adding Debug_vlog, however, causes Debug.S to also print
// while flushing the plist, which happens concurrently. // while flushing the plist, which happens concurrently.
if Ctxt.Debugvlog || Flag.LowerD != "" || Flag.Live > 0 { if Ctxt.Debugvlog || Debug.Any() || Flag.Live > 0 {
return false return false
} }
// TODO: Test and delete this condition. // TODO: Test and delete this condition.

View File

@ -10,7 +10,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/dwarf" "cmd/internal/dwarf"
@ -112,6 +112,7 @@ func Main(archInit func(*Arch)) {
// pseudo-package used for methods with anonymous receivers // pseudo-package used for methods with anonymous receivers
gopkg = types.NewPkg("go", "") gopkg = types.NewPkg("go", "")
DebugSSA = ssa.PhaseOption
ParseFlags() ParseFlags()
// Record flags that affect the build result. (And don't // Record flags that affect the build result. (And don't