go/src/cmd/compile/fmt_test.go

724 lines
23 KiB
Go
Raw Normal View History

// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements TestFormats; a test that verifies
// format strings in the compiler (this directory and all
// subdirectories, recursively).
//
// TestFormats finds potential (Printf, etc.) format strings.
// If they are used in a call, the format verbs are verified
// based on the matching argument type against a precomputed
// table of valid formats. The knownFormats table can be used
// to automatically rewrite format strings with the -u flag.
//
// A new knownFormats table based on the found formats is printed
// when the test is run in verbose mode (-v flag). The table
// needs to be updated whenever a new (type, format) combination
// is found and the format verb is not 'v' or 'T' (as in "%v" or
// "%T").
//
// Run as: go test -run Formats [-u][-v]
//
// Known bugs:
// - indexed format strings ("%[2]s", etc.) are not supported
// (the test will fail)
// - format strings that are not simple string literals cannot
// be updated automatically
// (the test will fail with respective warnings)
// - format strings in _test packages outside the current
// package are not processed
// (the test will report those files)
//
package main_test
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/build"
"go/constant"
"go/format"
"go/importer"
"go/parser"
"go/token"
"go/types"
"internal/testenv"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"testing"
"unicode/utf8"
)
var update = flag.Bool("u", false, "update format strings")
// The following variables collect information across all processed files.
var (
fset = token.NewFileSet()
formatStrings = make(map[*ast.BasicLit]bool) // set of all potential format strings found
foundFormats = make(map[string]bool) // set of all formats found
callSites = make(map[*ast.CallExpr]*callSite) // map of all calls
)
// A File is a corresponding (filename, ast) pair.
type File struct {
name string
ast *ast.File
}
func TestFormats(t *testing.T) {
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
// process all directories
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if info.Name() == "testdata" {
return filepath.SkipDir
}
importPath := filepath.Join("cmd/compile", path)
if blacklistedPackages[filepath.ToSlash(importPath)] {
return filepath.SkipDir
}
pkg, err := build.Import(importPath, path, 0)
if err != nil {
if _, ok := err.(*build.NoGoError); ok {
return nil // nothing to do here
}
t.Fatal(err)
}
collectPkgFormats(t, pkg)
}
return nil
})
// test and rewrite formats
updatedFiles := make(map[string]File) // files that were rewritten
for _, p := range callSites {
// test current format literal and determine updated one
out := formatReplace(p.str, func(index int, in string) string {
if in == "*" {
return in // cannot rewrite '*' (as in "%*d")
}
// in != '*'
typ := p.types[index]
format := typ + " " + in // e.g., "*Node %n"
// check if format is known
out, known := knownFormats[format]
// record format if not yet found
_, found := foundFormats[format]
if !found {
foundFormats[format] = true
}
// report an error if the format is unknown and this is the first
// time we see it; ignore "%v" and "%T" which are always valid
if !known && !found && in != "%v" && in != "%T" {
t.Errorf("%s: unknown format %q for %s argument", posString(p.arg), in, typ)
}
if out == "" {
out = in
}
return out
})
// replace existing format literal if it changed
if out != p.str {
// we cannot replace the argument if it's not a string literal for now
// (e.g., it may be "foo" + "bar")
lit, ok := p.arg.(*ast.BasicLit)
if !ok {
delete(callSites, p.call) // treat as if we hadn't found this site
continue
}
if testing.Verbose() {
fmt.Printf("%s:\n\t- %q\n\t+ %q\n", posString(p.arg), p.str, out)
}
// find argument index of format argument
index := -1
for i, arg := range p.call.Args {
if p.arg == arg {
index = i
break
}
}
if index < 0 {
// we may have processed the same call site twice,
// but that shouldn't happen
panic("internal error: matching argument not found")
}
// replace literal
new := *lit // make a copy
new.Value = strconv.Quote(out) // this may introduce "-quotes where there were `-quotes
p.call.Args[index] = &new
updatedFiles[p.file.name] = p.file
}
}
// write dirty files back
var filesUpdated bool
if len(updatedFiles) > 0 && *update {
for _, file := range updatedFiles {
var buf bytes.Buffer
if err := format.Node(&buf, fset, file.ast); err != nil {
t.Errorf("WARNING: formatting %s failed: %v", file.name, err)
continue
}
if err := ioutil.WriteFile(file.name, buf.Bytes(), 0x666); err != nil {
t.Errorf("WARNING: writing %s failed: %v", file.name, err)
continue
}
fmt.Printf("updated %s\n", file.name)
filesUpdated = true
}
}
// report all function names containing a format string
if len(callSites) > 0 && testing.Verbose() {
set := make(map[string]bool)
for _, p := range callSites {
set[nodeString(p.call.Fun)] = true
}
var list []string
for s := range set {
list = append(list, s)
}
fmt.Println("\nFunctions")
printList(list)
}
// report all formats found
if len(foundFormats) > 0 && testing.Verbose() {
var list []string
for s := range foundFormats {
list = append(list, fmt.Sprintf("%q: \"\",", s))
}
fmt.Println("\nvar knownFormats = map[string]string{")
printList(list)
fmt.Println("}")
}
// check that knownFormats is up to date
if !testing.Verbose() && !*update {
var mismatch bool
for s := range foundFormats {
if _, ok := knownFormats[s]; !ok {
mismatch = true
break
}
}
if !mismatch {
for s := range knownFormats {
if _, ok := foundFormats[s]; !ok {
mismatch = true
break
}
}
}
if mismatch {
cmd/compile: add line numbers to values & blocks in ssa.html In order to improve the line numbering for debuggers, it's necessary to trace lines through compilation. This makes it (much) easier to follow. The format of the last column of the ssa.html output was also changed to reduce the spamminess of the file name, which is usually the same and makes it far harder to read instructions and line numbers, and to make it wider and also able to break words when wrapping (long path names still can push off the end otherwise; side-to-side scrolling was tried but was more annoying than the occasional wrapped line). Sample output now, where [...] is elision for sake of making the CL character-counter happy -- and the (##) line numbers are rendered in italics and a smaller font (11 point) under control of a CSS class "line-number". genssa # /Users/drchase/[...]/ssa/testdata/hist.go 00000 (35) TEXT "".main(SB) 00001 (35) FUNCDATA $0, gclocals·7be4bb[...]1e8b(SB) 00002 (35) FUNCDATA $1, gclocals·9ab98a[...]4568(SB) v920 00003 (36) LEAQ ""..autotmp_31-640(SP), DI v858 00004 (36) XORPS X0, X0 v6 00005 (36) LEAQ -48(DI), DI v6 00006 (36) DUFFZERO $277 v576 00007 (36) LEAQ ""..autotmp_31-640(SP), AX v10 00008 (36) TESTB AX, (AX) b1 00009 (36) JMP 10 and from an earlier phase: b18: ← b17 v242 (47) = Copy <mem> v238 v243 (47) = VarKill <mem> {.autotmp_16} v242 v244 (48) = Addr <**bufio.Scanner> {scanner} v2 v245 (48) = Load <*bufio.Scanner> v244 v243 [...] v279 (49) = Store <mem> {int64} v277 v276 v278 v280 (49) = Addr <*error> {.autotmp_18} v2 v281 (49) = Load <error> v280 v279 v282 (49) = Addr <*error> {err} v2 v283 (49) = VarDef <mem> {err} v279 v284 (49) = Store <mem> {error} v282 v281 v283 v285 (47) = VarKill <mem> {.autotmp_18} v284 v286 (47) = VarKill <mem> {.autotmp_17} v285 v287 (50) = Addr <*error> {err} v2 v288 (50) = Load <error> v287 v286 v289 (50) = NeqInter <bool> v288 v51 If v289 → b21 b22 (line 50) Change-Id: I3f46310918f965761f59e6f03ea53067237c28a8 Reviewed-on: https://go-review.googlesource.com/69591 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-10-10 14:44:15 -04:00
t.Errorf("knownFormats is out of date; please 'go test -v fmt_test.go > foo', then extract new definition of knownFormats from foo")
}
}
// all format strings of calls must be in the formatStrings set (self-verification)
for _, p := range callSites {
if lit, ok := p.arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
if formatStrings[lit] {
// ok
delete(formatStrings, lit)
} else {
// this should never happen
panic(fmt.Sprintf("internal error: format string not found (%s)", posString(lit)))
}
}
}
// if we have any strings left, we may need to update them manually
if len(formatStrings) > 0 && filesUpdated {
var list []string
for lit := range formatStrings {
list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit)))
}
fmt.Println("\nWARNING: Potentially missed format strings")
printList(list)
t.Fail()
}
fmt.Println()
}
// A callSite describes a function call that appears to contain
// a format string.
type callSite struct {
file File
call *ast.CallExpr // call containing the format string
arg ast.Expr // format argument (string literal or constant)
str string // unquoted format string
types []string // argument types
}
func collectPkgFormats(t *testing.T, pkg *build.Package) {
// collect all files
var filenames []string
filenames = append(filenames, pkg.GoFiles...)
filenames = append(filenames, pkg.CgoFiles...)
filenames = append(filenames, pkg.TestGoFiles...)
// TODO(gri) verify _test files outside package
for _, name := range pkg.XTestGoFiles {
// don't process this test itself
if name != "fmt_test.go" && testing.Verbose() {
fmt.Printf("WARNING: %s not processed\n", filepath.Join(pkg.Dir, name))
}
}
// make filenames relative to .
for i, name := range filenames {
filenames[i] = filepath.Join(pkg.Dir, name)
}
// parse all files
files := make([]*ast.File, len(filenames))
for i, filename := range filenames {
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
files[i] = f
}
// typecheck package
conf := types.Config{Importer: importer.Default()}
etypes := make(map[ast.Expr]types.TypeAndValue)
if _, err := conf.Check(pkg.ImportPath, fset, files, &types.Info{Types: etypes}); err != nil {
t.Fatal(err)
}
// collect all potential format strings (for extra verification later)
for _, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if s, ok := stringLit(n); ok && isFormat(s) {
formatStrings[n.(*ast.BasicLit)] = true
}
return true
})
}
// collect all formats/arguments of calls with format strings
for index, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if call, ok := n.(*ast.CallExpr); ok {
// ignore blacklisted functions
if blacklistedFunctions[nodeString(call.Fun)] {
return true
}
// look for an arguments that might be a format string
for i, arg := range call.Args {
if s, ok := stringVal(etypes[arg]); ok && isFormat(s) {
// make sure we have enough arguments
n := numFormatArgs(s)
if i+1+n > len(call.Args) {
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
break // ignore this call
}
// assume last n arguments are to be formatted;
// determine their types
argTypes := make([]string, n)
for i, arg := range call.Args[len(call.Args)-n:] {
if tv, ok := etypes[arg]; ok {
argTypes[i] = typeString(tv.Type)
}
}
// collect call site
if callSites[call] != nil {
panic("internal error: file processed twice?")
}
callSites[call] = &callSite{
file: File{filenames[index], file},
call: call,
arg: arg,
str: s,
types: argTypes,
}
break // at most one format per argument list
}
}
}
return true
})
}
}
// printList prints list in sorted order.
func printList(list []string) {
sort.Strings(list)
for _, s := range list {
fmt.Println("\t", s)
}
}
// posString returns a string representation of n's position
// in the form filename:line:col: .
func posString(n ast.Node) string {
if n == nil {
return ""
}
return fset.Position(n.Pos()).String()
}
// nodeString returns a string representation of n.
func nodeString(n ast.Node) string {
var buf bytes.Buffer
if err := format.Node(&buf, fset, n); err != nil {
log.Fatal(err) // should always succeed
}
return buf.String()
}
// typeString returns a string representation of n.
func typeString(typ types.Type) string {
return filepath.ToSlash(typ.String())
}
// stringLit returns the unquoted string value and true if
// n represents a string literal; otherwise it returns ""
// and false.
func stringLit(n ast.Node) (string, bool) {
if lit, ok := n.(*ast.BasicLit); ok && lit.Kind == token.STRING {
s, err := strconv.Unquote(lit.Value)
if err != nil {
log.Fatal(err) // should not happen with correct ASTs
}
return s, true
}
return "", false
}
// stringVal returns the (unquoted) string value and true if
// tv is a string constant; otherwise it returns "" and false.
func stringVal(tv types.TypeAndValue) (string, bool) {
if tv.IsValue() && tv.Value != nil && tv.Value.Kind() == constant.String {
return constant.StringVal(tv.Value), true
}
return "", false
}
// formatIter iterates through the string s in increasing
// index order and calls f for each format specifier '%..v'.
// The arguments for f describe the specifier's index range.
// If a format specifier contains a "*", f is called with
// the index range for "*" alone, before being called for
// the entire specifier. The result of f is the index of
// the rune at which iteration continues.
func formatIter(s string, f func(i, j int) int) {
i := 0 // index after current rune
var r rune // current rune
next := func() {
r1, w := utf8.DecodeRuneInString(s[i:])
if w == 0 {
r1 = -1 // signal end-of-string
}
r = r1
i += w
}
flags := func() {
for r == ' ' || r == '#' || r == '+' || r == '-' || r == '0' {
next()
}
}
index := func() {
if r == '[' {
log.Fatalf("cannot handle indexed arguments: %s", s)
}
}
digits := func() {
index()
if r == '*' {
i = f(i-1, i)
next()
return
}
for '0' <= r && r <= '9' {
next()
}
}
for next(); r >= 0; next() {
if r == '%' {
i0 := i
next()
flags()
digits()
if r == '.' {
next()
digits()
}
index()
// accept any letter (a-z, A-Z) as format verb;
// ignore anything else
if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' {
i = f(i0-1, i)
}
}
}
}
// isFormat reports whether s contains format specifiers.
func isFormat(s string) (yes bool) {
formatIter(s, func(i, j int) int {
yes = true
return len(s) // stop iteration
})
return
}
// oneFormat reports whether s is exactly one format specifier.
func oneFormat(s string) (yes bool) {
formatIter(s, func(i, j int) int {
yes = i == 0 && j == len(s)
return j
})
return
}
// numFormatArgs returns the number of format specifiers in s.
func numFormatArgs(s string) int {
count := 0
formatIter(s, func(i, j int) int {
count++
return j
})
return count
}
// formatReplace replaces the i'th format specifier s in the incoming
// string in with the result of f(i, s) and returns the new string.
func formatReplace(in string, f func(i int, s string) string) string {
var buf []byte
i0 := 0
index := 0
formatIter(in, func(i, j int) int {
if sub := in[i:j]; sub != "*" { // ignore calls for "*" width/length specifiers
buf = append(buf, in[i0:i]...)
buf = append(buf, f(index, sub)...)
i0 = j
}
index++
return j
})
return string(append(buf, in[i0:]...))
}
// blacklistedPackages is the set of packages which can
// be ignored.
var blacklistedPackages = map[string]bool{}
// blacklistedFunctions is the set of functions which may have
// format-like arguments but which don't do any formatting and
// thus may be ignored.
var blacklistedFunctions = map[string]bool{}
func init() {
// verify that knownFormats entries are correctly formatted
for key, val := range knownFormats {
// key must be "typename format", and format starts with a '%'
// (formats containing '*' alone are not collected in this table)
i := strings.Index(key, "%")
if i < 0 || !oneFormat(key[i:]) {
log.Fatalf("incorrect knownFormats key: %q", key)
}
// val must be "format" or ""
if val != "" && !oneFormat(val) {
log.Fatalf("incorrect knownFormats value: %q (key = %q)", val, key)
}
}
}
// knownFormats entries are of the form "typename format" -> "newformat".
// An absent entry means that the format is not recognized as valid.
// An empty new format means that the format should remain unchanged.
// To print out a new table, run: go test -run Formats -v.
var knownFormats = map[string]string{
"*bytes.Buffer %s": "",
"*cmd/compile/internal/gc.Mpflt %v": "",
"*cmd/compile/internal/gc.Mpint %v": "",
"*cmd/compile/internal/gc.Node %#v": "",
"*cmd/compile/internal/gc.Node %+S": "",
"*cmd/compile/internal/gc.Node %+v": "",
"*cmd/compile/internal/gc.Node %0j": "",
"*cmd/compile/internal/gc.Node %L": "",
"*cmd/compile/internal/gc.Node %S": "",
"*cmd/compile/internal/gc.Node %j": "",
"*cmd/compile/internal/gc.Node %p": "",
"*cmd/compile/internal/gc.Node %v": "",
"*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "",
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
"*cmd/compile/internal/ssa.Func %v": "",
"*cmd/compile/internal/ssa.Register %s": "",
cmd/compile: reimplement location list generation Completely redesign and reimplement location list generation to be more efficient, and hopefully not too hard to understand. RegKills are gone. Instead of using the regalloc's liveness calculations, redo them using the Ops' clobber information. Besides saving a lot of Values, this avoids adding RegKills to blocks that would be empty otherwise, which was messing up optimizations. This does mean that it's much harder to tell whether the generation process is buggy (there's nothing to cross-check it with), and there may be disagreements with GC liveness. But the performance gain is significant, and it's nice not to be messing with earlier compiler phases. The intermediate representations are gone. Instead of producing ssa.BlockDebugs, then dwarf.LocationLists, and then finally real location lists, go directly from the SSA to a (mostly) real location list. Because the SSA analysis happens before assembly, it stores encoded block/value IDs where PCs would normally go. It would be easier to do the SSA analysis after assembly, but I didn't want to retain the SSA just for that. Generation proceeds in two phases: first, it traverses the function in CFG order, storing the state of the block at the beginning and end. End states are used to produce the start states of the successor blocks. In the second phase, it traverses in program text order and produces the location lists. The processing in the second phase is redundant, but much cheaper than storing the intermediate representation. It might be possible to combine the two phases somewhat to take advantage of cases where the CFG matches the block layout, but I haven't tried. Location lists are finalized by adding a base address selection entry, translating each encoded block/value ID to a real PC, and adding the terminating zero entry. This probably won't work on OSX, where dsymutil will choke on the base address selection. I tried emitting CU-relative relocations for each address, and it was *very* bad for performance -- it uses more memory storing all the relocations than it does for the actual location list bytes. I think I'm going to end up synthesizing the relocations in the linker only on OSX, but TBD. TestNexting needs updating: with more optimizations working, the debugger doesn't stop on the continue (line 88) any more, and the test's duplicate suppression kicks in. Also, dx and dy live a little longer now, but they have the correct values. Change-Id: Ie772dfe23a4e389ca573624fac4d05401ae32307 Reviewed-on: https://go-review.googlesource.com/89356 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
2017-10-26 15:40:17 -04:00
"*cmd/compile/internal/ssa.Register %v": "",
"*cmd/compile/internal/ssa.SparseTreeNode %v": "",
"*cmd/compile/internal/ssa.Value %s": "",
"*cmd/compile/internal/ssa.Value %v": "",
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"*cmd/compile/internal/types.Field %p": "",
"*cmd/compile/internal/types.Field %v": "",
"*cmd/compile/internal/types.Sym %+v": "",
"*cmd/compile/internal/types.Sym %0S": "",
"*cmd/compile/internal/types.Sym %S": "",
"*cmd/compile/internal/types.Sym %p": "",
"*cmd/compile/internal/types.Sym %v": "",
"*cmd/compile/internal/types.Type %#v": "",
"*cmd/compile/internal/types.Type %+v": "",
"*cmd/compile/internal/types.Type %-S": "",
"*cmd/compile/internal/types.Type %0S": "",
"*cmd/compile/internal/types.Type %L": "",
"*cmd/compile/internal/types.Type %S": "",
"*cmd/compile/internal/types.Type %p": "",
cmd/compile: change ssa.Type into *types.Type When package ssa was created, Type was in package gc. To avoid circular dependencies, we used an interface (ssa.Type) to represent type information in SSA. In the Go 1.9 cycle, gri extricated the Type type from package gc. As a result, we can now use it in package ssa. Now, instead of package types depending on package ssa, it is the other way. This is a more sensible dependency tree, and helps compiler performance a bit. Though this is a big CL, most of the changes are mechanical and uninteresting. Interesting bits: * Add new singleton globals to package types for the special SSA types Memory, Void, Invalid, Flags, and Int128. * Add two new Types, TSSA for the special types, and TTUPLE, for SSA tuple types. ssa.MakeTuple is now types.NewTuple. * Move type comparison result constants CMPlt, CMPeq, and CMPgt to package types. * We had picked the name "types" in our rules for the handy list of types provided by ssa.Config. That conflicted with the types package name, so change it to "typ". * Update the type comparison routine to handle tuples and special types inline. * Teach gc/fmt.go how to print special types. * We can now eliminate ElemTypes in favor of just Elem, and probably also some other duplicated Type methods designed to return ssa.Type instead of *types.Type. * The ssa tests were using their own dummy types, and they were not particularly careful about types in general. Of necessity, this CL switches them to use *types.Type; it does not make them more type-accurate. Unfortunately, using types.Type means initializing a bit of the types universe. This is prime for refactoring and improvement. This shrinks ssa.Value; it now fits in a smaller size class on 64 bit systems. This doesn't have a giant impact, though, since most Values are preallocated in a chunk. name old alloc/op new alloc/op delta Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8) Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10) GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10) Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10) GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9) Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8) Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10) XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10) [Geo mean] 40.5MB 40.3MB -0.68% name old allocs/op new allocs/op delta Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9) Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10) GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10) Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10) GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9) Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8) Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10) XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10) [Geo mean] 428k 428k -0.01% Removing all the interface calls helps non-trivially with CPU, though. name old time/op new time/op delta Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96) Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96) GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96) Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99) GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97) Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99) Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94) XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95) [Geo mean] 178ms 173ms -2.65% name old user-time/op new user-time/op delta Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99) Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95) GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99) Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96) GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100) Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92) Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100) XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97) [Geo mean] 220ms 213ms -2.76% Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1 Reviewed-on: https://go-review.googlesource.com/42145 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
"*cmd/compile/internal/types.Type %s": "",
"*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
"*math/big.Int %#x": "",
"*math/big.Int %s": "",
cmd/compile: add indexed export format This CL introduces a new indexed data format for package export data. This improves on the previous (sequential) binary format by allowing the compiler to selectively (and lazily) load only the data that's actually needed for compilation. In large Go projects, the package export data can become very large due to transitive type declaration dependencies and inline function/method bodies. By lazily loading these declarations and bodies as needed, we avoid wasting time and memory processing unnecessary and/or redundant data. In the benchmarks below, "old" is -iexport=false and "new" is -iexport=true. The suffixes indicate the compiler concurrency (-c) and inlining (-l) settings used for the build (using -gcflags=all=-foo). Benchmarks were run on an HP Z620. Juju is "go build -a github.com/juju/juju/cmd/...": name old real-time/op new real-time/op delta Juju/c=1/l=0 44.0s ± 1% 38.7s ± 9% -11.97% (p=0.001 n=7+7) Juju/c=1/l=4 53.7s ± 3% 45.3s ± 4% -15.53% (p=0.001 n=7+7) Juju/c=4/l=0 39.7s ± 8% 32.0s ± 4% -19.38% (p=0.001 n=7+7) Juju/c=4/l=4 46.3s ± 4% 38.0s ± 4% -18.06% (p=0.001 n=7+7) name old user-time/op new user-time/op delta Juju/c=1/l=0 371s ± 1% 300s ± 0% -19.07% (p=0.001 n=7+6) Juju/c=1/l=4 482s ± 0% 374s ± 1% -22.37% (p=0.001 n=7+7) Juju/c=4/l=0 410s ± 1% 340s ± 1% -17.19% (p=0.001 n=7+7) Juju/c=4/l=4 532s ± 1% 424s ± 1% -20.26% (p=0.001 n=7+7) name old sys-time/op new sys-time/op delta Juju/c=1/l=0 33.4s ± 1% 28.4s ± 2% -15.02% (p=0.001 n=7+7) Juju/c=1/l=4 40.7s ± 2% 32.8s ± 3% -19.51% (p=0.001 n=7+7) Juju/c=4/l=0 39.8s ± 2% 34.4s ± 2% -13.74% (p=0.001 n=7+7) Juju/c=4/l=4 48.4s ± 2% 40.4s ± 2% -16.50% (p=0.001 n=7+7) Kubelet is "go build -a k8s.io/kubernetes/cmd/kubelet": name old real-time/op new real-time/op delta Kubelet/c=1/l=0 42.0s ± 1% 34.8s ± 1% -17.27% (p=0.008 n=5+5) Kubelet/c=1/l=4 55.4s ± 3% 45.4s ± 3% -18.06% (p=0.002 n=6+6) Kubelet/c=4/l=0 37.4s ± 3% 29.9s ± 1% -20.25% (p=0.004 n=6+5) Kubelet/c=4/l=4 48.1s ± 2% 39.0s ± 5% -18.93% (p=0.002 n=6+6) name old user-time/op new user-time/op delta Kubelet/c=1/l=0 291s ± 1% 233s ± 1% -19.96% (p=0.002 n=6+6) Kubelet/c=1/l=4 385s ± 1% 298s ± 1% -22.51% (p=0.002 n=6+6) Kubelet/c=4/l=0 325s ± 0% 268s ± 1% -17.48% (p=0.004 n=5+6) Kubelet/c=4/l=4 429s ± 1% 343s ± 1% -20.08% (p=0.002 n=6+6) name old sys-time/op new sys-time/op delta Kubelet/c=1/l=0 25.1s ± 2% 20.9s ± 4% -16.69% (p=0.002 n=6+6) Kubelet/c=1/l=4 31.2s ± 3% 24.4s ± 0% -21.67% (p=0.010 n=6+4) Kubelet/c=4/l=0 30.2s ± 2% 25.6s ± 1% -15.34% (p=0.002 n=6+6) Kubelet/c=4/l=4 37.3s ± 1% 30.9s ± 2% -17.11% (p=0.002 n=6+6) Change-Id: Ie43eb3bbe1392cbb61c86792a17a57b33b9561f0 Reviewed-on: https://go-review.googlesource.com/106796 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-01 01:55:55 -07:00
"*math/big.Int %v": "",
"[16]byte %x": "",
"[]*cmd/compile/internal/gc.Node %v": "",
cmd/compile: reimplement location list generation Completely redesign and reimplement location list generation to be more efficient, and hopefully not too hard to understand. RegKills are gone. Instead of using the regalloc's liveness calculations, redo them using the Ops' clobber information. Besides saving a lot of Values, this avoids adding RegKills to blocks that would be empty otherwise, which was messing up optimizations. This does mean that it's much harder to tell whether the generation process is buggy (there's nothing to cross-check it with), and there may be disagreements with GC liveness. But the performance gain is significant, and it's nice not to be messing with earlier compiler phases. The intermediate representations are gone. Instead of producing ssa.BlockDebugs, then dwarf.LocationLists, and then finally real location lists, go directly from the SSA to a (mostly) real location list. Because the SSA analysis happens before assembly, it stores encoded block/value IDs where PCs would normally go. It would be easier to do the SSA analysis after assembly, but I didn't want to retain the SSA just for that. Generation proceeds in two phases: first, it traverses the function in CFG order, storing the state of the block at the beginning and end. End states are used to produce the start states of the successor blocks. In the second phase, it traverses in program text order and produces the location lists. The processing in the second phase is redundant, but much cheaper than storing the intermediate representation. It might be possible to combine the two phases somewhat to take advantage of cases where the CFG matches the block layout, but I haven't tried. Location lists are finalized by adding a base address selection entry, translating each encoded block/value ID to a real PC, and adding the terminating zero entry. This probably won't work on OSX, where dsymutil will choke on the base address selection. I tried emitting CU-relative relocations for each address, and it was *very* bad for performance -- it uses more memory storing all the relocations than it does for the actual location list bytes. I think I'm going to end up synthesizing the relocations in the linker only on OSX, but TBD. TestNexting needs updating: with more optimizations working, the debugger doesn't stop on the continue (line 88) any more, and the test's duplicate suppression kicks in. Also, dx and dy live a little longer now, but they have the correct values. Change-Id: Ie772dfe23a4e389ca573624fac4d05401ae32307 Reviewed-on: https://go-review.googlesource.com/89356 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
2017-10-26 15:40:17 -04:00
"[]*cmd/compile/internal/ssa.Block %v": "",
"[]*cmd/compile/internal/ssa.Value %v": "",
"[][]string %q": "",
"[]byte %s": "",
"[]byte %x": "",
"[]cmd/compile/internal/ssa.Edge %v": "",
"[]cmd/compile/internal/ssa.ID %v": "",
"[]cmd/compile/internal/syntax.token %s": "",
"[]string %v": "",
"bool %v": "",
"byte %08b": "",
"byte %c": "",
cmd/compile: add indexed export format This CL introduces a new indexed data format for package export data. This improves on the previous (sequential) binary format by allowing the compiler to selectively (and lazily) load only the data that's actually needed for compilation. In large Go projects, the package export data can become very large due to transitive type declaration dependencies and inline function/method bodies. By lazily loading these declarations and bodies as needed, we avoid wasting time and memory processing unnecessary and/or redundant data. In the benchmarks below, "old" is -iexport=false and "new" is -iexport=true. The suffixes indicate the compiler concurrency (-c) and inlining (-l) settings used for the build (using -gcflags=all=-foo). Benchmarks were run on an HP Z620. Juju is "go build -a github.com/juju/juju/cmd/...": name old real-time/op new real-time/op delta Juju/c=1/l=0 44.0s ± 1% 38.7s ± 9% -11.97% (p=0.001 n=7+7) Juju/c=1/l=4 53.7s ± 3% 45.3s ± 4% -15.53% (p=0.001 n=7+7) Juju/c=4/l=0 39.7s ± 8% 32.0s ± 4% -19.38% (p=0.001 n=7+7) Juju/c=4/l=4 46.3s ± 4% 38.0s ± 4% -18.06% (p=0.001 n=7+7) name old user-time/op new user-time/op delta Juju/c=1/l=0 371s ± 1% 300s ± 0% -19.07% (p=0.001 n=7+6) Juju/c=1/l=4 482s ± 0% 374s ± 1% -22.37% (p=0.001 n=7+7) Juju/c=4/l=0 410s ± 1% 340s ± 1% -17.19% (p=0.001 n=7+7) Juju/c=4/l=4 532s ± 1% 424s ± 1% -20.26% (p=0.001 n=7+7) name old sys-time/op new sys-time/op delta Juju/c=1/l=0 33.4s ± 1% 28.4s ± 2% -15.02% (p=0.001 n=7+7) Juju/c=1/l=4 40.7s ± 2% 32.8s ± 3% -19.51% (p=0.001 n=7+7) Juju/c=4/l=0 39.8s ± 2% 34.4s ± 2% -13.74% (p=0.001 n=7+7) Juju/c=4/l=4 48.4s ± 2% 40.4s ± 2% -16.50% (p=0.001 n=7+7) Kubelet is "go build -a k8s.io/kubernetes/cmd/kubelet": name old real-time/op new real-time/op delta Kubelet/c=1/l=0 42.0s ± 1% 34.8s ± 1% -17.27% (p=0.008 n=5+5) Kubelet/c=1/l=4 55.4s ± 3% 45.4s ± 3% -18.06% (p=0.002 n=6+6) Kubelet/c=4/l=0 37.4s ± 3% 29.9s ± 1% -20.25% (p=0.004 n=6+5) Kubelet/c=4/l=4 48.1s ± 2% 39.0s ± 5% -18.93% (p=0.002 n=6+6) name old user-time/op new user-time/op delta Kubelet/c=1/l=0 291s ± 1% 233s ± 1% -19.96% (p=0.002 n=6+6) Kubelet/c=1/l=4 385s ± 1% 298s ± 1% -22.51% (p=0.002 n=6+6) Kubelet/c=4/l=0 325s ± 0% 268s ± 1% -17.48% (p=0.004 n=5+6) Kubelet/c=4/l=4 429s ± 1% 343s ± 1% -20.08% (p=0.002 n=6+6) name old sys-time/op new sys-time/op delta Kubelet/c=1/l=0 25.1s ± 2% 20.9s ± 4% -16.69% (p=0.002 n=6+6) Kubelet/c=1/l=4 31.2s ± 3% 24.4s ± 0% -21.67% (p=0.010 n=6+4) Kubelet/c=4/l=0 30.2s ± 2% 25.6s ± 1% -15.34% (p=0.002 n=6+6) Kubelet/c=4/l=4 37.3s ± 1% 30.9s ± 2% -17.11% (p=0.002 n=6+6) Change-Id: Ie43eb3bbe1392cbb61c86792a17a57b33b9561f0 Reviewed-on: https://go-review.googlesource.com/106796 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-01 01:55:55 -07:00
"byte %v": "",
"cmd/compile/internal/arm.shift %d": "",
"cmd/compile/internal/gc.Class %d": "",
"cmd/compile/internal/gc.Class %s": "",
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
"cmd/compile/internal/gc.Class %v": "",
"cmd/compile/internal/gc.Ctype %d": "",
"cmd/compile/internal/gc.Ctype %v": "",
"cmd/compile/internal/gc.Level %d": "",
"cmd/compile/internal/gc.Level %v": "",
"cmd/compile/internal/gc.Nodes %#v": "",
"cmd/compile/internal/gc.Nodes %+v": "",
"cmd/compile/internal/gc.Nodes %.v": "",
"cmd/compile/internal/gc.Nodes %v": "",
"cmd/compile/internal/gc.Op %#v": "",
"cmd/compile/internal/gc.Op %v": "",
"cmd/compile/internal/gc.Val %#v": "",
"cmd/compile/internal/gc.Val %T": "",
"cmd/compile/internal/gc.Val %v": "",
cmd/compile: eliminate fmtmode and fmtpkgpfx globals The fmtmode and fmtpkgpfx globals stand in the way of making the compiler more concurrent (#15756). This CL removes them. The natural way to eliminate a global is to explicitly thread it as a parameter through all function calls. However, most of the functions in gc/fmt.go get called indirectly, by way of fmt format strings, so there's nowhere natural to add a parameter. Since there are only a few fmtmode modes, use named types to distinguish between modes. For example, fmtNodeErr, fmtNodeDbg, and fmtNodeTypeId are all gc.Node, but they print in different modes. Varying the type allows us to thread mode through fmt. Handle fmtpkgpfx by converting it to a printing mode, FTypeIdName, and using the same type-based approach. To avoid a loss of readability and danger of bugs from introducing conversions at all call sites, instead add a helper that systematically modifies the args. The only remaining gc/fmt.go global is dumpdepth. Since that is used for debugging only, it that can be handled with a global mutex, or some similarly basic, if inefficient, protection. Passes toolstash -cmp. No compiler performance impact. For future reference, other options for threading state that were considered and rejected: * Wrapping values in structs, such as: type fmtNode struct { n *Node mode fmtMode } This reduces the proliferation of types, and supports easily adding extra local parameters. However, putting such a struct into an interface{} allocates. This is unacceptable in this particular area of code. * Passing state via precision, such as: fmt.Fprintf("%*v", mode, n) where mode is the state encoded as an integer. This avoids extra allocations, but it is out of keeping with the intended semantics of precision, and is less readable. * Modify the fmt package to support setting/getting context via fmt.State. Unavailable due to Go 1 compatibility, and probably the wrong solution anyway. * Give up on package fmt. This would be a huge readability regression and cause high code churn. * Attempt a de-novo rewrite that circumvents these problems. Too high a risk of bugs, with insufficient reward for the effort, particularly since long term plans call for elimination of gc.Node. Change-Id: Iea2440d5a34a938e64273707de27e3a897cb41d1 Reviewed-on: https://go-review.googlesource.com/38147 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
2016-11-07 16:14:32 -08:00
"cmd/compile/internal/gc.fmtMode %d": "",
"cmd/compile/internal/gc.initKind %d": "",
cmd/compile: add indexed export format This CL introduces a new indexed data format for package export data. This improves on the previous (sequential) binary format by allowing the compiler to selectively (and lazily) load only the data that's actually needed for compilation. In large Go projects, the package export data can become very large due to transitive type declaration dependencies and inline function/method bodies. By lazily loading these declarations and bodies as needed, we avoid wasting time and memory processing unnecessary and/or redundant data. In the benchmarks below, "old" is -iexport=false and "new" is -iexport=true. The suffixes indicate the compiler concurrency (-c) and inlining (-l) settings used for the build (using -gcflags=all=-foo). Benchmarks were run on an HP Z620. Juju is "go build -a github.com/juju/juju/cmd/...": name old real-time/op new real-time/op delta Juju/c=1/l=0 44.0s ± 1% 38.7s ± 9% -11.97% (p=0.001 n=7+7) Juju/c=1/l=4 53.7s ± 3% 45.3s ± 4% -15.53% (p=0.001 n=7+7) Juju/c=4/l=0 39.7s ± 8% 32.0s ± 4% -19.38% (p=0.001 n=7+7) Juju/c=4/l=4 46.3s ± 4% 38.0s ± 4% -18.06% (p=0.001 n=7+7) name old user-time/op new user-time/op delta Juju/c=1/l=0 371s ± 1% 300s ± 0% -19.07% (p=0.001 n=7+6) Juju/c=1/l=4 482s ± 0% 374s ± 1% -22.37% (p=0.001 n=7+7) Juju/c=4/l=0 410s ± 1% 340s ± 1% -17.19% (p=0.001 n=7+7) Juju/c=4/l=4 532s ± 1% 424s ± 1% -20.26% (p=0.001 n=7+7) name old sys-time/op new sys-time/op delta Juju/c=1/l=0 33.4s ± 1% 28.4s ± 2% -15.02% (p=0.001 n=7+7) Juju/c=1/l=4 40.7s ± 2% 32.8s ± 3% -19.51% (p=0.001 n=7+7) Juju/c=4/l=0 39.8s ± 2% 34.4s ± 2% -13.74% (p=0.001 n=7+7) Juju/c=4/l=4 48.4s ± 2% 40.4s ± 2% -16.50% (p=0.001 n=7+7) Kubelet is "go build -a k8s.io/kubernetes/cmd/kubelet": name old real-time/op new real-time/op delta Kubelet/c=1/l=0 42.0s ± 1% 34.8s ± 1% -17.27% (p=0.008 n=5+5) Kubelet/c=1/l=4 55.4s ± 3% 45.4s ± 3% -18.06% (p=0.002 n=6+6) Kubelet/c=4/l=0 37.4s ± 3% 29.9s ± 1% -20.25% (p=0.004 n=6+5) Kubelet/c=4/l=4 48.1s ± 2% 39.0s ± 5% -18.93% (p=0.002 n=6+6) name old user-time/op new user-time/op delta Kubelet/c=1/l=0 291s ± 1% 233s ± 1% -19.96% (p=0.002 n=6+6) Kubelet/c=1/l=4 385s ± 1% 298s ± 1% -22.51% (p=0.002 n=6+6) Kubelet/c=4/l=0 325s ± 0% 268s ± 1% -17.48% (p=0.004 n=5+6) Kubelet/c=4/l=4 429s ± 1% 343s ± 1% -20.08% (p=0.002 n=6+6) name old sys-time/op new sys-time/op delta Kubelet/c=1/l=0 25.1s ± 2% 20.9s ± 4% -16.69% (p=0.002 n=6+6) Kubelet/c=1/l=4 31.2s ± 3% 24.4s ± 0% -21.67% (p=0.010 n=6+4) Kubelet/c=4/l=0 30.2s ± 2% 25.6s ± 1% -15.34% (p=0.002 n=6+6) Kubelet/c=4/l=4 37.3s ± 1% 30.9s ± 2% -17.11% (p=0.002 n=6+6) Change-Id: Ie43eb3bbe1392cbb61c86792a17a57b33b9561f0 Reviewed-on: https://go-review.googlesource.com/106796 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-01 01:55:55 -07:00
"cmd/compile/internal/gc.itag %v": "",
"cmd/compile/internal/ssa.BranchPrediction %d": "",
"cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "",
"cmd/compile/internal/ssa.ID %d": "",
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
"cmd/compile/internal/ssa.ID %v": "",
"cmd/compile/internal/ssa.LocalSlot %s": "",
cmd/compile: reimplement location list generation Completely redesign and reimplement location list generation to be more efficient, and hopefully not too hard to understand. RegKills are gone. Instead of using the regalloc's liveness calculations, redo them using the Ops' clobber information. Besides saving a lot of Values, this avoids adding RegKills to blocks that would be empty otherwise, which was messing up optimizations. This does mean that it's much harder to tell whether the generation process is buggy (there's nothing to cross-check it with), and there may be disagreements with GC liveness. But the performance gain is significant, and it's nice not to be messing with earlier compiler phases. The intermediate representations are gone. Instead of producing ssa.BlockDebugs, then dwarf.LocationLists, and then finally real location lists, go directly from the SSA to a (mostly) real location list. Because the SSA analysis happens before assembly, it stores encoded block/value IDs where PCs would normally go. It would be easier to do the SSA analysis after assembly, but I didn't want to retain the SSA just for that. Generation proceeds in two phases: first, it traverses the function in CFG order, storing the state of the block at the beginning and end. End states are used to produce the start states of the successor blocks. In the second phase, it traverses in program text order and produces the location lists. The processing in the second phase is redundant, but much cheaper than storing the intermediate representation. It might be possible to combine the two phases somewhat to take advantage of cases where the CFG matches the block layout, but I haven't tried. Location lists are finalized by adding a base address selection entry, translating each encoded block/value ID to a real PC, and adding the terminating zero entry. This probably won't work on OSX, where dsymutil will choke on the base address selection. I tried emitting CU-relative relocations for each address, and it was *very* bad for performance -- it uses more memory storing all the relocations than it does for the actual location list bytes. I think I'm going to end up synthesizing the relocations in the linker only on OSX, but TBD. TestNexting needs updating: with more optimizations working, the debugger doesn't stop on the continue (line 88) any more, and the test's duplicate suppression kicks in. Also, dx and dy live a little longer now, but they have the correct values. Change-Id: Ie772dfe23a4e389ca573624fac4d05401ae32307 Reviewed-on: https://go-review.googlesource.com/89356 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
2017-10-26 15:40:17 -04:00
"cmd/compile/internal/ssa.LocalSlot %v": "",
"cmd/compile/internal/ssa.Location %s": "",
"cmd/compile/internal/ssa.Op %s": "",
"cmd/compile/internal/ssa.Op %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "",
"cmd/compile/internal/syntax.Expr %#v": "",
"cmd/compile/internal/syntax.Node %T": "",
"cmd/compile/internal/syntax.Operator %s": "",
cmd/compile/internal/syntax: remove dependency on cmd/internal/src For dependency reasons, the data structure implementing source positions in the compiler is in cmd/internal/src. It contains highly compiler specific details (e.g. inlining index). This change introduces a parallel but simpler position representation, defined in the syntax package, which removes that package's dependency on cmd/internal/src, and also removes the need to deal with certain filename-specific operations (defined by the needs of the compiler) in the syntax package. As a result, the syntax package becomes again a compiler- independent, stand-alone package that at some point might replace (or augment) the existing top-level go/* syntax-related packages. Additionally, line directives that update column numbers are now correctly tracked through the syntax package, with additional tests added. (The respective changes also need to be made in cmd/internal/src; i.e., the compiler accepts but still ignores column numbers in line directives.) This change comes at the cost of a new position translation step, but that step is cheap because it only needs to do real work if the position base changed (i.e., if there is a new file, or new line directive). There is no noticeable impact on overall compiler performance measured with `compilebench -count 5 -alloc`: name old time/op new time/op delta Template 220ms ± 8% 228ms ±18% ~ (p=0.548 n=5+5) Unicode 119ms ±11% 113ms ± 5% ~ (p=0.056 n=5+5) GoTypes 684ms ± 6% 677ms ± 3% ~ (p=0.841 n=5+5) Compiler 3.19s ± 7% 3.01s ± 1% ~ (p=0.095 n=5+5) SSA 7.92s ± 8% 7.79s ± 1% ~ (p=0.690 n=5+5) Flate 141ms ± 7% 139ms ± 4% ~ (p=0.548 n=5+5) GoParser 173ms ±12% 171ms ± 4% ~ (p=1.000 n=5+5) Reflect 417ms ± 5% 411ms ± 3% ~ (p=0.548 n=5+5) Tar 205ms ± 5% 198ms ± 2% ~ (p=0.690 n=5+5) XML 232ms ± 4% 229ms ± 4% ~ (p=0.690 n=5+5) StdCmd 28.7s ± 5% 28.2s ± 2% ~ (p=0.421 n=5+5) name old user-time/op new user-time/op delta Template 269ms ± 4% 265ms ± 5% ~ (p=0.421 n=5+5) Unicode 153ms ± 7% 149ms ± 3% ~ (p=0.841 n=5+5) GoTypes 850ms ± 7% 862ms ± 4% ~ (p=0.841 n=5+5) Compiler 4.01s ± 5% 3.86s ± 0% ~ (p=0.190 n=5+4) SSA 10.9s ± 4% 10.8s ± 2% ~ (p=0.548 n=5+5) Flate 166ms ± 7% 167ms ± 6% ~ (p=1.000 n=5+5) GoParser 204ms ± 8% 206ms ± 7% ~ (p=0.841 n=5+5) Reflect 514ms ± 5% 508ms ± 4% ~ (p=0.548 n=5+5) Tar 245ms ± 6% 244ms ± 3% ~ (p=0.690 n=5+5) XML 280ms ± 4% 278ms ± 4% ~ (p=0.841 n=5+5) name old alloc/op new alloc/op delta Template 37.9MB ± 0% 37.9MB ± 0% ~ (p=0.841 n=5+5) Unicode 28.8MB ± 0% 28.8MB ± 0% ~ (p=0.841 n=5+5) GoTypes 113MB ± 0% 113MB ± 0% ~ (p=0.151 n=5+5) Compiler 468MB ± 0% 468MB ± 0% -0.01% (p=0.032 n=5+5) SSA 1.50GB ± 0% 1.50GB ± 0% ~ (p=0.548 n=5+5) Flate 24.4MB ± 0% 24.4MB ± 0% ~ (p=1.000 n=5+5) GoParser 30.7MB ± 0% 30.7MB ± 0% ~ (p=1.000 n=5+5) Reflect 76.5MB ± 0% 76.5MB ± 0% ~ (p=0.548 n=5+5) Tar 38.9MB ± 0% 38.9MB ± 0% ~ (p=0.222 n=5+5) XML 41.6MB ± 0% 41.6MB ± 0% ~ (p=0.548 n=5+5) name old allocs/op new allocs/op delta Template 382k ± 0% 382k ± 0% +0.01% (p=0.008 n=5+5) Unicode 343k ± 0% 343k ± 0% ~ (p=0.841 n=5+5) GoTypes 1.19M ± 0% 1.19M ± 0% +0.01% (p=0.008 n=5+5) Compiler 4.53M ± 0% 4.53M ± 0% +0.03% (p=0.008 n=5+5) SSA 12.4M ± 0% 12.4M ± 0% +0.00% (p=0.008 n=5+5) Flate 235k ± 0% 235k ± 0% ~ (p=0.079 n=5+5) GoParser 318k ± 0% 318k ± 0% ~ (p=0.730 n=5+5) Reflect 978k ± 0% 978k ± 0% ~ (p=1.000 n=5+5) Tar 393k ± 0% 393k ± 0% ~ (p=0.056 n=5+5) XML 405k ± 0% 405k ± 0% ~ (p=0.548 n=5+5) name old text-bytes new text-bytes delta HelloSize 672kB ± 0% 672kB ± 0% ~ (all equal) CmdGoSize 7.12MB ± 0% 7.12MB ± 0% ~ (all equal) name old data-bytes new data-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) CmdGoSize 390kB ± 0% 390kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.07MB ± 0% 1.07MB ± 0% ~ (all equal) CmdGoSize 11.2MB ± 0% 11.2MB ± 0% ~ (all equal) Passes toolstash compare. For #22662. Change-Id: I19edb53dd9675af57f7122cb7dba2a6d8bdcc3da Reviewed-on: https://go-review.googlesource.com/94515 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2018-01-02 16:58:37 -08:00
"cmd/compile/internal/syntax.Pos %s": "",
"cmd/compile/internal/syntax.Pos %v": "",
"cmd/compile/internal/syntax.position %s": "",
"cmd/compile/internal/syntax.token %q": "",
"cmd/compile/internal/syntax.token %s": "",
"cmd/compile/internal/types.EType %d": "",
"cmd/compile/internal/types.EType %s": "",
"cmd/compile/internal/types.EType %v": "",
"error %v": "",
"float64 %.2f": "",
"float64 %.3f": "",
"float64 %.6g": "",
"float64 %g": "",
"int %-12d": "",
"int %-6d": "",
"int %-8o": "",
"int %02d": "",
"int %6d": "",
"int %c": "",
"int %d": "",
"int %v": "",
"int %x": "",
"int16 %d": "",
"int16 %x": "",
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %.5d": "",
"int64 %X": "",
"int64 %d": "",
"int64 %v": "",
"int64 %x": "",
"int8 %d": "",
"int8 %x": "",
"interface{} %#v": "",
"interface{} %T": "",
"interface{} %q": "",
"interface{} %s": "",
"interface{} %v": "",
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
"reflect.Type %s": "",
"rune %#U": "",
"rune %c": "",
cmd/compile: provide a way to auto-discover -d debug keys Currently one needs to refer to the sources to have a list of accepted debug keys. We can copy what 'ssa/help' does and introspect the list of debug keys to print a more detailed help: $ go tool compile -d help usage: -d arg[,arg]* and arg is <key>[=<value>] <key> is one of: append print information about append compilation closure print information about closure compilation disablenil disable nil checks dclstack run internal dclstack check gcprog print dump of GC programs nil print information about nil checks panic do not hide any compiler panic slice print information about slice compilation typeassert print information about type assertion inlining wb print information about write barriers export print export data pctab print named pc-value table ssa/help print help about SSA debugging <value> is key-specific. Key "pctab" supports values: "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata" For '-d help' to be discoverable, a hint is given in the -d flag description. A last thing, today at least one go file needs to be provided to get to the code printing ssa/help. $ go tool compile -d ssa/help foo.go Add a check so one can just do '-d help' or '-d ssa/help' Caught by trybot: I needed to update fmt_test.go as I'm introducing the usage of %-*s in a format string. Fixes #20041 Change-Id: Ib2858b038c1bcbe644aa3b1a371009710c6d957d Reviewed-on: https://go-review.googlesource.com/41091 Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
2017-04-19 19:24:27 +01:00
"string %-*s": "",
"string %-16s": "",
"string %-6s": "",
"string %.*s": "",
"string %q": "",
"string %s": "",
"string %v": "",
"time.Duration %d": "",
"time.Duration %v": "",
"uint %04x": "",
"uint %5d": "",
"uint %d": "",
"uint %x": "",
"uint16 %d": "",
"uint16 %v": "",
"uint16 %x": "",
"uint32 %d": "",
"uint32 %x": "",
"uint64 %08x": "",
"uint64 %d": "",
"uint64 %x": "",
"uint8 %d": "",
"uint8 %x": "",
"uintptr %d": "",
}