From 8ce2605c5b4bc64432e1711a1273f91eee3a41fc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sat, 5 Dec 2020 00:02:46 -0500 Subject: [PATCH] [dev.regabi] cmd/compile: untangle ir.Dump printing The Node printing code is tangled up due to the multiple printing modes. Split out the Dump mode into its own code, which clarifies it considerably. We are going to have to change the code for the new Node representations, so it is nice to have it in an understandable form first. The output of Dump is unchanged except for the removal of spurious mid-Dump blank lines that have been printed for a while but don't really make sense and appear to be a bug. The %+v verb on Op prints the name ("ADD" not "+"), matching %+v on Node and %+v on Nodes to get Dump and DumpList formats. Passes buildall w/ toolstash -cmp. Change-Id: I07f0f245859f1f785e10bdd671855ca43c51b545 Reviewed-on: https://go-review.googlesource.com/c/go/+/275774 Trust: Russ Cox Reviewed-by: Matthew Dempsky --- src/cmd/compile/fmtmap_test.go | 4 +- src/cmd/compile/internal/ir/fmt.go | 272 +++++++++++++++-------------- 2 files changed, 144 insertions(+), 132 deletions(-) diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go index fde9c51b27..bf81cc07db 100644 --- a/src/cmd/compile/fmtmap_test.go +++ b/src/cmd/compile/fmtmap_test.go @@ -42,12 +42,14 @@ var knownFormats = map[string]string{ "*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 %#L": "", "*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": "", @@ -88,7 +90,6 @@ var knownFormats = map[string]string{ "cmd/compile/internal/ir.Node %+v": "", "cmd/compile/internal/ir.Node %L": "", "cmd/compile/internal/ir.Node %S": "", - "cmd/compile/internal/ir.Node %j": "", "cmd/compile/internal/ir.Node %p": "", "cmd/compile/internal/ir.Node %v": "", "cmd/compile/internal/ir.Nodes %#v": "", @@ -97,6 +98,7 @@ var knownFormats = map[string]string{ "cmd/compile/internal/ir.Nodes %v": "", "cmd/compile/internal/ir.Ntype %v": "", "cmd/compile/internal/ir.Op %#v": "", + "cmd/compile/internal/ir.Op %+v": "", "cmd/compile/internal/ir.Op %v": "", "cmd/compile/internal/ssa.BranchPrediction %d": "", "cmd/compile/internal/ssa.Edge %v": "", diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index ae33dcddd7..b5bf036d5e 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -9,6 +9,7 @@ import ( "fmt" "go/constant" "io" + "os" "strconv" "strings" "sync" @@ -258,7 +259,10 @@ var OpNames = []string{ } func (o Op) GoString() string { - return fmt.Sprintf("%#v", o) + if int(o) < len(OpNames) && OpNames[o] != "" { + return OpNames[o] + } + return o.String() } type fmtOp struct { @@ -266,30 +270,20 @@ type fmtOp struct { m FmtMode } -func (f *fmtOp) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) } - -func (o Op) Format(s fmt.State, verb rune) { o.format(s, verb, FErr) } +func (f *fmtOp) Format(s fmt.State, verb rune) { f.x.Format(s, verb) } -func (o Op) format(s fmt.State, verb rune, mode FmtMode) { +func (o Op) Format(s fmt.State, verb rune) { switch verb { - case 'v': - o.oconv(s, fmtFlag(s, verb), mode) - default: fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o)) - } -} - -func (o Op) oconv(s fmt.State, flag FmtFlag, mode FmtMode) { - if flag&FmtSharp != 0 || mode != FDbg { - if int(o) < len(OpNames) && OpNames[o] != "" { - fmt.Fprint(s, OpNames[o]) + case 'v': + if s.Flag('+') { + // %+v is OMUL instead of "*" + io.WriteString(s, o.String()) return } + io.WriteString(s, o.GoString()) } - - // 'o.String()' instead of just 'o' to avoid infinite recursion - fmt.Fprint(s, o.String()) } // Val @@ -346,6 +340,9 @@ func (f *fmtSym) Format(s fmt.State, verb rune) { symFormat(f.x, s, verb, f.m) } func symFormat(s *types.Sym, f fmt.State, verb rune, mode FmtMode) { switch verb { case 'v', 'S': + if verb == 'v' && f.Flag('+') { + mode = FDbg + } fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode)) default: @@ -514,6 +511,9 @@ func (f *fmtType) Format(s fmt.State, verb rune) { typeFormat(f.x, s, verb, f.m) func typeFormat(t *types.Type, s fmt.State, verb rune, mode FmtMode) { switch verb { case 'v', 'S', 'L': + if verb == 'v' && s.Flag('+') { // %+v is debug format + mode = FDbg + } fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode)) default: fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t) @@ -897,6 +897,13 @@ type fmtNode struct { func (f *fmtNode) Format(s fmt.State, verb rune) { nodeFormat(f.x, s, verb, f.m) } func FmtNode(n Node, s fmt.State, verb rune) { + // %+v prints Dump. + if s.Flag('+') && verb == 'v' { + dumpNode(s, n, 1) + return + } + + // Otherwise print Go syntax. nodeFormat(n, s, verb, FErr) } @@ -905,9 +912,6 @@ func nodeFormat(n Node, s fmt.State, verb rune, mode FmtMode) { case 'v', 'S', 'L': nconvFmt(n, s, fmtFlag(s, verb), mode) - case 'j': - jconvFmt(n, s, fmtFlag(s, verb)) - default: fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n) } @@ -927,11 +931,6 @@ func nconvFmt(n Node, s fmt.State, flag FmtFlag, mode FmtMode) { case FErr: nodeFmt(n, s, flag, mode) - case FDbg: - dumpdepth++ - nodeDumpFmt(n, s, flag, mode) - dumpdepth-- - default: base.Fatalf("unhandled %%N mode: %d", mode) } @@ -1663,11 +1662,17 @@ type fmtNodes struct { m FmtMode } -func (f *fmtNodes) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) } +func (f *fmtNodes) Format(s fmt.State, verb rune) { f.x.format(s, verb, FErr) } func (l Nodes) Format(s fmt.State, verb rune) { l.format(s, verb, FErr) } func (l Nodes) format(s fmt.State, verb rune, mode FmtMode) { + if s.Flag('+') && verb == 'v' { + // %+v is DumpList output + dumpNodes(s, l, 1) + return + } + switch verb { case 'v': l.hconv(s, fmtFlag(s, verb), mode) @@ -1683,16 +1688,9 @@ func (n Nodes) String() string { // Flags: all those of %N plus '.': separate with comma's instead of semicolons. func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode FmtMode) { - if l.Len() == 0 && mode == FDbg { - fmt.Fprint(s, "") - return - } - flag, mode = flag.update(mode) sep := "; " - if mode == FDbg { - sep = "\n" - } else if flag&FmtComma != 0 { + if flag&FmtComma != 0 { sep = ", " } @@ -1707,44 +1705,45 @@ func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode FmtMode) { // Dump func Dump(s string, n Node) { - fmt.Printf("%s [%p]%+v\n", s, n, n) + fmt.Printf("%s [%p]%+v", s, n, n) } func DumpList(s string, l Nodes) { - fmt.Printf("%s%+v\n", s, l) + var buf bytes.Buffer + FDumpList(&buf, s, l) + os.Stdout.Write(buf.Bytes()) } func FDumpList(w io.Writer, s string, l Nodes) { - fmt.Fprintf(w, "%s%+v\n", s, l) + io.WriteString(w, s) + dumpNodes(w, l, 1) + io.WriteString(w, "\n") } -// TODO(gri) make variable local somehow -var dumpdepth int - -// indent prints indentation to s. -func indent(s fmt.State) { - fmt.Fprint(s, "\n") - for i := 0; i < dumpdepth; i++ { - fmt.Fprint(s, ". ") +// indent prints indentation to w. +func indent(w io.Writer, depth int) { + fmt.Fprint(w, "\n") + for i := 0; i < depth; i++ { + fmt.Fprint(w, ". ") } } // EscFmt is set by the escape analysis code to add escape analysis details to the node print. var EscFmt func(n Node) string -// *Node details -func jconvFmt(n Node, s fmt.State, flag FmtFlag) { +// dumpNodeHeader prints the debug-format node header line to w. +func dumpNodeHeader(w io.Writer, n Node) { // Useful to see which nodes in an AST printout are actually identical if base.Debug.DumpPtrs != 0 { - fmt.Fprintf(s, " p(%p)", n) + fmt.Fprintf(w, " p(%p)", n) } if n.Name() != nil && n.Name().Vargen != 0 { - fmt.Fprintf(s, " g(%d)", n.Name().Vargen) + fmt.Fprintf(w, " g(%d)", n.Name().Vargen) } if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil { // Useful to see where Defn is set and what node it points to - fmt.Fprintf(s, " defn(%p)", n.Name().Defn) + fmt.Fprintf(w, " defn(%p)", n.Name().Defn) } if n.Pos().IsKnown() { @@ -1755,168 +1754,179 @@ func jconvFmt(n Node, s fmt.State, flag FmtFlag) { case src.PosIsStmt: pfx = "+" } - fmt.Fprintf(s, " l(%s%d)", pfx, n.Pos().Line()) + fmt.Fprintf(w, " l(%s%d)", pfx, n.Pos().Line()) } if n.Offset() != types.BADWIDTH { - fmt.Fprintf(s, " x(%d)", n.Offset()) + fmt.Fprintf(w, " x(%d)", n.Offset()) } if n.Class() != 0 { - fmt.Fprintf(s, " class(%v)", n.Class()) + fmt.Fprintf(w, " class(%v)", n.Class()) } if n.Colas() { - fmt.Fprintf(s, " colas(%v)", n.Colas()) + fmt.Fprintf(w, " colas(%v)", n.Colas()) } if EscFmt != nil { if esc := EscFmt(n); esc != "" { - fmt.Fprintf(s, " %s", esc) + fmt.Fprintf(w, " %s", esc) } } if n.Typecheck() != 0 { - fmt.Fprintf(s, " tc(%d)", n.Typecheck()) + fmt.Fprintf(w, " tc(%d)", n.Typecheck()) } if n.IsDDD() { - fmt.Fprintf(s, " isddd(%v)", n.IsDDD()) + fmt.Fprintf(w, " isddd(%v)", n.IsDDD()) } if n.Implicit() { - fmt.Fprintf(s, " implicit(%v)", n.Implicit()) + fmt.Fprintf(w, " implicit(%v)", n.Implicit()) } if n.Op() == ONAME { if n.Name().Addrtaken() { - fmt.Fprint(s, " addrtaken") + fmt.Fprint(w, " addrtaken") } if n.Name().Assigned() { - fmt.Fprint(s, " assigned") + fmt.Fprint(w, " assigned") } if n.Name().IsClosureVar() { - fmt.Fprint(s, " closurevar") + fmt.Fprint(w, " closurevar") } if n.Name().Captured() { - fmt.Fprint(s, " captured") + fmt.Fprint(w, " captured") } if n.Name().IsOutputParamHeapAddr() { - fmt.Fprint(s, " outputparamheapaddr") + fmt.Fprint(w, " outputparamheapaddr") } } if n.Bounded() { - fmt.Fprint(s, " bounded") + fmt.Fprint(w, " bounded") } if n.NonNil() { - fmt.Fprint(s, " nonnil") + fmt.Fprint(w, " nonnil") } if n.HasCall() { - fmt.Fprint(s, " hascall") + fmt.Fprint(w, " hascall") } if n.Name() != nil && n.Name().Used() { - fmt.Fprint(s, " used") + fmt.Fprint(w, " used") } } -func nodeDumpFmt(n Node, s fmt.State, flag FmtFlag, mode FmtMode) { - recur := flag&FmtShort == 0 - - if recur { - indent(s) - if dumpdepth > 40 { - fmt.Fprint(s, "...") - return - } +func dumpNode(w io.Writer, n Node, depth int) { + indent(w, depth) + if depth > 40 { + fmt.Fprint(w, "...") + return + } - if n.Init().Len() != 0 { - mode.Fprintf(s, "%v-init%v", n.Op(), n.Init()) - indent(s) - } + if n.Init().Len() != 0 { + fmt.Fprintf(w, "%+v-init", n.Op()) + dumpNodes(w, n.Init(), depth+1) + indent(w, depth) } switch n.Op() { default: - mode.Fprintf(s, "%v%j", n.Op(), n) + fmt.Fprintf(w, "%+v", n.Op()) + dumpNodeHeader(w, n) case OLITERAL: - mode.Fprintf(s, "%v-%v%j", n.Op(), n.Val(), n) + fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val()) + dumpNodeHeader(w, n) case ONAME, ONONAME, OMETHEXPR: if n.Sym() != nil { - mode.Fprintf(s, "%v-%v%j", n.Op(), n.Sym(), n) + fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym()) } else { - mode.Fprintf(s, "%v%j", n.Op(), n) + fmt.Fprintf(w, "%+v", n.Op()) } - if recur && n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil { - indent(s) - mode.Fprintf(s, "%v-ntype%v", n.Op(), n.Name().Ntype) + dumpNodeHeader(w, n) + if n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil { + indent(w, depth) + fmt.Fprintf(w, "%+v-ntype", n.Op()) + dumpNode(w, n.Name().Ntype, depth+1) } case OASOP: - mode.Fprintf(s, "%v-%v%j", n.Op(), n.SubOp(), n) + fmt.Fprintf(w, "%+v-%+v", n.Op(), n.SubOp()) + dumpNodeHeader(w, n) case OTYPE: - mode.Fprintf(s, "%v %v%j type=%v", n.Op(), n.Sym(), n, n.Type()) - if recur && n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil { - indent(s) - mode.Fprintf(s, "%v-ntype%v", n.Op(), n.Name().Ntype) + fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym()) + dumpNodeHeader(w, n) + fmt.Fprintf(w, " type=%+v", n.Type()) + if n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil { + indent(w, depth) + fmt.Fprintf(w, "%+v-ntype", n.Op()) + dumpNode(w, n.Name().Ntype, depth+1) } } if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Nname.Sym() != nil { - mode.Fprintf(s, " fnName %v", n.Func().Nname.Sym()) + fmt.Fprintf(w, " fnName %+v", n.Func().Nname.Sym()) } if n.Sym() != nil && n.Op() != ONAME { - mode.Fprintf(s, " %v", n.Sym()) + fmt.Fprintf(w, " %+v", n.Sym()) } if n.Type() != nil { - mode.Fprintf(s, " %v", n.Type()) + fmt.Fprintf(w, " %+v", n.Type()) } - if recur { - if n.Left() != nil { - mode.Fprintf(s, "%v", n.Left()) - } - if n.Right() != nil { - mode.Fprintf(s, "%v", n.Right()) - } - if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Body().Len() != 0 { - indent(s) - // The function associated with a closure - mode.Fprintf(s, "%v-clofunc%v", n.Op(), n.Func()) - } - if n.Op() == ODCLFUNC && n.Func() != nil && n.Func().Dcl != nil && len(n.Func().Dcl) != 0 { - indent(s) - // The dcls for a func or closure - mode.Fprintf(s, "%v-dcl%v", n.Op(), asNameNodes(n.Func().Dcl)) - } - if n.List().Len() != 0 { - indent(s) - mode.Fprintf(s, "%v-list%v", n.Op(), n.List()) + if n.Left() != nil { + dumpNode(w, n.Left(), depth+1) + } + if n.Right() != nil { + dumpNode(w, n.Right(), depth+1) + } + if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Body().Len() != 0 { + indent(w, depth) + // The function associated with a closure + fmt.Fprintf(w, "%+v-clofunc", n.Op()) + dumpNode(w, n.Func(), depth+1) + } + if n.Op() == ODCLFUNC && n.Func() != nil && n.Func().Dcl != nil && len(n.Func().Dcl) != 0 { + indent(w, depth) + // The dcls for a func or closure + fmt.Fprintf(w, "%+v-dcl", n.Op()) + for _, dcl := range n.Func().Dcl { + dumpNode(w, dcl, depth+1) } + } + if n.List().Len() != 0 { + indent(w, depth) + fmt.Fprintf(w, "%+v-list", n.Op()) + dumpNodes(w, n.List(), depth+1) + } - if n.Rlist().Len() != 0 { - indent(s) - mode.Fprintf(s, "%v-rlist%v", n.Op(), n.Rlist()) - } + if n.Rlist().Len() != 0 { + indent(w, depth) + fmt.Fprintf(w, "%+v-rlist", n.Op()) + dumpNodes(w, n.Rlist(), depth+1) + } - if n.Body().Len() != 0 { - indent(s) - mode.Fprintf(s, "%v-body%v", n.Op(), n.Body()) - } + if n.Body().Len() != 0 { + indent(w, depth) + fmt.Fprintf(w, "%+v-body", n.Op()) + dumpNodes(w, n.Body(), depth+1) } } -// asNameNodes copies list to a new Nodes. -// It should only be called in debug formatting and other low-performance contexts. -func asNameNodes(list []*Name) Nodes { - var ns Nodes - for _, n := range list { - ns.Append(n) +func dumpNodes(w io.Writer, list Nodes, depth int) { + if list.Len() == 0 { + fmt.Fprintf(w, " ") + return + } + + for _, n := range list.Slice() { + dumpNode(w, n, depth) } - return ns } -- 2.48.1