1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
19 "cmd/compile/internal/base"
20 "cmd/compile/internal/types"
26 var OpNames = []string{
30 OALIGNOF: "unsafe.Alignof",
38 OCALL: "function call", // not actual syntax
45 OCONTINUE: "continue",
73 OOFFSETOF: "unsafe.Offsetof",
88 OSIZEOF: "unsafe.Sizeof",
91 OUNSAFEADD: "unsafe.Add",
92 OUNSAFESLICE: "unsafe.Slice",
93 OUNSAFESLICEDATA: "unsafe.SliceData",
94 OUNSAFESTRING: "unsafe.String",
95 OUNSAFESTRINGDATA: "unsafe.StringData",
99 // GoString returns the Go syntax for the Op, or else its name.
100 func (o Op) GoString() string {
101 if int(o) < len(OpNames) && OpNames[o] != "" {
107 // Format implements formatting for an Op.
108 // The valid formats are:
110 // %v Go syntax ("+", "<-", "print")
111 // %+v Debug syntax ("ADD", "RECV", "PRINT")
112 func (o Op) Format(s fmt.State, verb rune) {
115 fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
118 // %+v is OMUL instead of "*"
119 io.WriteString(s, o.String())
122 io.WriteString(s, o.GoString())
128 // fmtNode implements formatting for a Node n.
129 // Every Node implementation must define a Format method that calls fmtNode.
130 // The valid formats are:
133 // %L Go syntax followed by " (type T)" if type is known.
134 // %+v Debug syntax, as in Dump.
135 func fmtNode(n Node, s fmt.State, verb rune) {
137 // Otherwise we print Go syntax.
138 if s.Flag('+') && verb == 'v' {
143 if verb != 'v' && verb != 'S' && verb != 'L' {
144 fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
149 fmt.Fprint(s, "<nil>")
154 if verb == 'L' && t != nil {
155 if t.Kind() == types.TNIL {
157 } else if n.Op() == ONAME && n.Name().AutoTemp() {
158 fmt.Fprintf(s, "%v value", t)
160 fmt.Fprintf(s, "%v (type %v)", n, t)
165 // TODO inlining produces expressions with ninits. we can't print these yet.
167 if OpPrec[n.Op()] < 0 {
226 OUNSAFESTRINGDATA: 8,
273 // Statements handled by stmtfmt
301 // StmtWithInit reports whether op is a statement with an explicit init list.
302 func StmtWithInit(op Op) bool {
304 case OIF, OFOR, OSWITCH:
310 func stmtFmt(n Node, s fmt.State) {
311 // NOTE(rsc): This code used to support the text-based
312 // which was more aggressive about printing full Go syntax
313 // (for example, an actual loop instead of "for loop").
314 // The code is preserved for now in case we want to expand
315 // any of those shortenings later. Or maybe we will delete
316 // the code. But for now, keep it.
317 const exportFormat = false
319 // some statements allow for an init, but at most one,
320 // but we may have an arbitrary number added, eg by typecheck
321 // and inlining. If it doesn't fit the syntax, emit an enclosing
322 // block starting with the init statements.
324 // if we can just say "for" n->ninit; ... then do so
325 simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op())
327 // otherwise, print the inits as separate statements
328 complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat
330 // but if it was for if/for/switch, put in an extra surrounding block to limit the scope
331 extrablock := complexinit && StmtWithInit(n.Op())
338 fmt.Fprintf(s, " %v; ", n.Init())
344 fmt.Fprintf(s, "var %v %v", n.X.Sym(), n.X.Type())
346 // Don't export "v = <N>" initializing statements, hope they're always
347 // preceded by the DCL which will be re-parsed and typechecked to reproduce
348 // the "v = <N>" again.
351 if n.Def && !complexinit {
352 fmt.Fprintf(s, "%v := %v", n.X, n.Y)
354 fmt.Fprintf(s, "%v = %v", n.X, n.Y)
358 n := n.(*AssignOpStmt)
361 fmt.Fprintf(s, "%v++", n.X)
363 fmt.Fprintf(s, "%v--", n.X)
368 fmt.Fprintf(s, "%v %v= %v", n.X, n.AsOp, n.Y)
370 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
371 n := n.(*AssignListStmt)
372 if n.Def && !complexinit {
373 fmt.Fprintf(s, "%.v := %.v", n.Lhs, n.Rhs)
375 fmt.Fprintf(s, "%.v = %.v", n.Lhs, n.Rhs)
380 if len(n.List) != 0 {
381 fmt.Fprintf(s, "%v", n.List)
386 fmt.Fprintf(s, "return %.v", n.Results)
389 n := n.(*TailCallStmt)
390 fmt.Fprintf(s, "tailcall %v", n.Call)
393 n := n.(*InlineMarkStmt)
394 fmt.Fprintf(s, "inlmark %d", n.Index)
397 n := n.(*GoDeferStmt)
398 fmt.Fprintf(s, "go %v", n.Call)
401 n := n.(*GoDeferStmt)
402 fmt.Fprintf(s, "defer %v", n.Call)
407 fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body)
409 fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body)
411 if len(n.Else) != 0 {
412 fmt.Fprintf(s, " else { %v }", n.Else)
417 if !exportFormat { // TODO maybe only if FmtShort, same below
418 fmt.Fprintf(s, "for loop")
424 fmt.Fprint(s, " /* distinct */")
427 fmt.Fprintf(s, " %v;", n.Init()[0])
428 } else if n.Post != nil {
433 fmt.Fprintf(s, " %v", n.Cond)
437 fmt.Fprintf(s, "; %v", n.Post)
438 } else if simpleinit {
442 fmt.Fprintf(s, " { %v }", n.Body)
447 fmt.Fprint(s, "for loop")
453 fmt.Fprintf(s, " %v", n.Key)
455 fmt.Fprintf(s, ", %v", n.Value)
459 fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
461 fmt.Fprint(s, " /* distinct vars */")
467 fmt.Fprintf(s, "%v statement", n.Op())
470 fmt.Fprintf(s, "select { %v }", n.Cases)
475 fmt.Fprintf(s, "%v statement", n.Op())
478 fmt.Fprintf(s, "switch")
480 fmt.Fprintf(s, " %v;", n.Init()[0])
483 fmt.Fprintf(s, " %v ", n.Tag)
485 fmt.Fprintf(s, " { %v }", n.Cases)
489 if len(n.List) != 0 {
490 fmt.Fprintf(s, "case %.v", n.List)
492 fmt.Fprint(s, "default")
494 fmt.Fprintf(s, ": %v", n.Body)
496 case OBREAK, OCONTINUE, OGOTO, OFALL:
499 fmt.Fprintf(s, "%v %v", n.Op(), n.Label)
501 fmt.Fprintf(s, "%v", n.Op())
506 fmt.Fprintf(s, "%v: ", n.Label)
514 func exprFmt(n Node, s fmt.State, prec int) {
515 // NOTE(rsc): This code used to support the text-based
516 // which was more aggressive about printing full Go syntax
517 // (for example, an actual loop instead of "for loop").
518 // The code is preserved for now in case we want to expand
519 // any of those shortenings later. Or maybe we will delete
520 // the code. But for now, keep it.
521 const exportFormat = false
525 fmt.Fprint(s, "<nil>")
529 // We always want the original, if any.
530 if o := Orig(n); o != n {
535 // Skip implicit operations introduced during typechecking.
536 switch nn := n; nn.Op() {
549 case OCONV, OCONVNOP, OCONVIFACE, OCONVIDATA:
560 nprec := OpPrec[n.Op()]
561 if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() {
562 nprec = OpPrec[ODEREF]
566 fmt.Fprintf(s, "(%v)", n)
573 fmt.Fprintf(s, "(%v)", n.X)
580 fmt.Fprint(s, n.Sym())
587 // Special case for rune constants.
588 if typ == types.RuneType || typ == types.UntypedRune {
589 if x, ok := constant.Uint64Val(val); ok && x <= utf8.MaxRune {
590 fmt.Fprintf(s, "%q", x)
595 // Only include typ if it's neither the default nor untyped type
596 // for the constant value.
597 if k := val.Kind(); typ == types.Types[types.DefaultKinds[k]] || typ == types.UntypedTypes[k] {
600 fmt.Fprintf(s, "%v(%v)", typ, val)
605 if sym := n.Sym(); sym != nil {
609 fmt.Fprintf(s, "<unnamed Func>")
613 // Special case: name used as local variable in export.
614 // _ becomes ~b%d internally; print as _ for export
615 if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {
621 fmt.Fprint(s, n.Sym())
624 n := n.(*LinksymOffsetExpr)
625 fmt.Fprintf(s, "(%v)(%s@%d)", n.Type(), n.Linksym.Name, n.Offset_)
628 if n.Type() == nil && n.Sym() != nil {
629 fmt.Fprint(s, n.Sym())
632 fmt.Fprintf(s, "%v", n.Type())
635 n := n.(*ClosureExpr)
637 fmt.Fprint(s, "func literal")
640 fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func.Body)
643 n := n.(*CompLitExpr)
646 fmt.Fprintf(s, "... argument")
649 if typ := n.Type(); typ != nil {
650 fmt.Fprintf(s, "%v{%s}", typ, ellipsisIf(len(n.List) != 0))
653 fmt.Fprint(s, "composite literal")
656 fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
660 fmt.Fprintf(s, "&%v", n.X)
662 case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
663 n := n.(*CompLitExpr)
665 fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0))
668 fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
672 if n.Key != nil && n.Value != nil {
673 fmt.Fprintf(s, "%v:%v", n.Key, n.Value)
677 if n.Key == nil && n.Value != nil {
678 fmt.Fprintf(s, ":%v", n.Value)
681 if n.Key != nil && n.Value == nil {
682 fmt.Fprintf(s, "%v:", n.Key)
688 n := n.(*StructKeyExpr)
689 fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
691 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR:
692 n := n.(*SelectorExpr)
693 exprFmt(n.X, s, nprec)
695 fmt.Fprint(s, ".<nil>")
698 fmt.Fprintf(s, ".%s", n.Sel.Name)
700 case ODOTTYPE, ODOTTYPE2:
701 n := n.(*TypeAssertExpr)
702 exprFmt(n.X, s, nprec)
703 fmt.Fprintf(s, ".(%v)", n.Type())
705 case OINDEX, OINDEXMAP:
707 exprFmt(n.X, s, nprec)
708 fmt.Fprintf(s, "[%v]", n.Index)
710 case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
712 exprFmt(n.X, s, nprec)
719 fmt.Fprint(s, n.High)
721 if n.Op().IsSlice3() {
730 n := n.(*SliceHeaderExpr)
731 fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)
733 case OCOMPLEX, OCOPY, OUNSAFEADD, OUNSAFESLICE:
735 fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.X, n.Y)
749 if n.Type() == nil || n.Type().Sym() == nil {
750 fmt.Fprintf(s, "(%v)", n.Type())
752 fmt.Fprintf(s, "%v", n.Type())
754 fmt.Fprintf(s, "(%v)", n.X)
768 fmt.Fprintf(s, "%v(%v)", n.Op(), n.X)
780 fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.Args)
783 fmt.Fprintf(s, "%v(%.v)", n.Op(), n.Args)
785 case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
787 exprFmt(n.X, s, nprec)
789 fmt.Fprintf(s, "(%.v...)", n.Args)
792 fmt.Fprintf(s, "(%.v)", n.Args)
795 n := n.(*InlinedCallExpr)
796 // TODO(mdempsky): Print Init and/or Body?
797 if len(n.ReturnVars) == 1 {
798 fmt.Fprintf(s, "%v", n.ReturnVars[0])
801 fmt.Fprintf(s, "(.%v)", n.ReturnVars)
803 case OMAKEMAP, OMAKECHAN, OMAKESLICE:
806 fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Len, n.Cap)
809 if n.Len != nil && (n.Op() == OMAKESLICE || !n.Len.Type().IsUntyped()) {
810 fmt.Fprintf(s, "make(%v, %v)", n.Type(), n.Len)
813 fmt.Fprintf(s, "make(%v)", n.Type())
817 fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Len, n.Cap)
819 case OPLUS, ONEG, OBITNOT, ONOT, ORECV:
822 fmt.Fprintf(s, "%v", n.Op())
823 if n.X != nil && n.X.Op() == n.Op() {
826 exprFmt(n.X, s, nprec+1)
830 fmt.Fprintf(s, "%v", n.Op())
831 if n.X != nil && n.X.Op() == n.Op() {
834 exprFmt(n.X, s, nprec+1)
838 fmt.Fprintf(s, "%v", n.Op())
839 exprFmt(n.X, s, nprec+1)
860 exprFmt(n.X, s, nprec)
861 fmt.Fprintf(s, " %v ", n.Op())
862 exprFmt(n.Y, s, nprec+1)
866 n := n.(*LogicalExpr)
867 exprFmt(n.X, s, nprec)
868 fmt.Fprintf(s, " %v ", n.Op())
869 exprFmt(n.Y, s, nprec+1)
873 exprFmt(n.Chan, s, nprec)
874 fmt.Fprintf(s, " <- ")
875 exprFmt(n.Value, s, nprec+1)
878 n := n.(*AddStringExpr)
879 for i, n1 := range n.List {
883 exprFmt(n1, s, nprec)
886 fmt.Fprintf(s, "<node %v>", n.Op())
890 func ellipsisIf(b bool) string {
899 // Format implements formatting for a Nodes.
900 // The valid formats are:
902 // %v Go syntax, semicolon-separated
903 // %.v Go syntax, comma-separated
904 // %+v Debug syntax, as in DumpList.
905 func (l Nodes) Format(s fmt.State, verb rune) {
906 if s.Flag('+') && verb == 'v' {
907 // %+v is DumpList output
913 fmt.Fprintf(s, "%%!%c(Nodes)", verb)
918 if _, ok := s.Precision(); ok { // %.v is expr list
922 for i, n := range l {
932 // Dump prints the message s followed by a debug dump of n.
933 func Dump(s string, n Node) {
934 fmt.Printf("%s%+v\n", s, n)
937 // DumpList prints the message s followed by a debug dump of each node in the list.
938 func DumpList(s string, list Nodes) {
940 FDumpList(&buf, s, list)
941 os.Stdout.Write(buf.Bytes())
944 // FDumpList prints to w the message s followed by a debug dump of each node in the list.
945 func FDumpList(w io.Writer, s string, list Nodes) {
947 dumpNodes(w, list, 1)
948 io.WriteString(w, "\n")
951 // indent prints indentation to w.
952 func indent(w io.Writer, depth int) {
954 for i := 0; i < depth; i++ {
959 // EscFmt is set by the escape analysis code to add escape analysis details to the node print.
960 var EscFmt func(n Node) string
962 // dumpNodeHeader prints the debug-format node header line to w.
963 func dumpNodeHeader(w io.Writer, n Node) {
964 // Useful to see which nodes in an AST printout are actually identical
965 if base.Debug.DumpPtrs != 0 {
966 fmt.Fprintf(w, " p(%p)", n)
969 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
970 // Useful to see where Defn is set and what node it points to
971 fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
974 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil {
975 // Useful to see where Defn is set and what node it points to
976 fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn)
978 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil {
979 // Useful to see where Defn is set and what node it points to
980 fmt.Fprintf(w, " outer(%p)", n.Name().Outer)
984 if esc := EscFmt(n); esc != "" {
985 fmt.Fprintf(w, " %s", esc)
989 if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {
990 fmt.Fprintf(w, " %+v", n.Sym())
993 // Print Node-specific fields of basic type in header line.
994 v := reflect.ValueOf(n).Elem()
997 for i := 0; i < nf; i++ {
999 if tf.PkgPath != "" {
1000 // skip unexported field - Interface will fail
1004 if reflect.Bool <= k && k <= reflect.Complex128 {
1005 name := strings.TrimSuffix(tf.Name, "_")
1007 vfi := vf.Interface()
1008 if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && vf.IsZero() {
1012 fmt.Fprintf(w, " %s", name)
1014 fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
1019 // Print Node-specific booleans by looking for methods.
1020 // Different v, t from above - want *Struct not Struct, for methods.
1021 v = reflect.ValueOf(n)
1024 for i := 0; i < nm; i++ {
1026 if tm.PkgPath != "" {
1027 // skip unexported method - call will fail
1032 if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
1033 // TODO(rsc): Remove the func/defer/recover wrapping,
1034 // which is guarding against panics in miniExpr,
1035 // once we get down to the simpler state in which
1036 // nodes have no getter methods that aren't allowed to be called.
1038 defer func() { recover() }()
1039 if m.Call(nil)[0].Bool() {
1040 name := strings.TrimSuffix(tm.Name, "_")
1041 fmt.Fprintf(w, " %s", name)
1047 if n.Op() == OCLOSURE {
1048 n := n.(*ClosureExpr)
1049 if fn := n.Func; fn != nil && fn.Nname.Sym() != nil {
1050 fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
1054 if n.Type() != nil {
1055 if n.Op() == OTYPE {
1056 fmt.Fprintf(w, " type")
1058 fmt.Fprintf(w, " %+v", n.Type())
1060 if n.Typecheck() != 0 {
1061 fmt.Fprintf(w, " tc(%d)", n.Typecheck())
1064 if n.Pos().IsKnown() {
1065 fmt.Fprint(w, " # ")
1066 switch n.Pos().IsStmt() {
1067 case src.PosNotStmt:
1068 fmt.Fprint(w, "_") // "-" would be confusing
1073 base.Ctxt.AllPos(n.Pos(), func(pos src.Pos) {
1076 // TODO(mdempsky): Print line pragma details too.
1077 file := filepath.Base(pos.Filename())
1078 // Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.
1079 fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())
1084 func dumpNode(w io.Writer, n Node, depth int) {
1087 fmt.Fprint(w, "...")
1092 fmt.Fprint(w, "NilIrNode")
1096 if len(n.Init()) != 0 {
1097 fmt.Fprintf(w, "%+v-init", n.Op())
1098 dumpNodes(w, n.Init(), depth+1)
1104 fmt.Fprintf(w, "%+v", n.Op())
1105 dumpNodeHeader(w, n)
1108 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())
1109 dumpNodeHeader(w, n)
1112 case ONAME, ONONAME:
1114 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym())
1116 fmt.Fprintf(w, "%+v", n.Op())
1118 dumpNodeHeader(w, n)
1121 case OLINKSYMOFFSET:
1122 n := n.(*LinksymOffsetExpr)
1123 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Linksym)
1124 // Offset is almost always 0, so only print when it's interesting.
1126 fmt.Fprintf(w, "%+v", n.Offset_)
1128 dumpNodeHeader(w, n)
1131 n := n.(*AssignOpStmt)
1132 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
1133 dumpNodeHeader(w, n)
1136 fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())
1137 dumpNodeHeader(w, n)
1141 fmt.Fprintf(w, "%+v", n.Op())
1142 dumpNodeHeader(w, n)
1145 // Func has many fields we don't want to print.
1146 // Bypass reflection and just print what we want.
1148 fmt.Fprintf(w, "%+v", n.Op())
1149 dumpNodeHeader(w, n)
1151 if len(fn.Dcl) > 0 {
1153 fmt.Fprintf(w, "%+v-Dcl", n.Op())
1154 for _, dcl := range n.Dcl {
1155 dumpNode(w, dcl, depth+1)
1158 if len(fn.ClosureVars) > 0 {
1160 fmt.Fprintf(w, "%+v-ClosureVars", n.Op())
1161 for _, cv := range fn.ClosureVars {
1162 dumpNode(w, cv, depth+1)
1165 if len(fn.Enter) > 0 {
1167 fmt.Fprintf(w, "%+v-Enter", n.Op())
1168 dumpNodes(w, fn.Enter, depth+1)
1170 if len(fn.Body) > 0 {
1172 fmt.Fprintf(w, "%+v-body", n.Op())
1173 dumpNodes(w, fn.Body, depth+1)
1178 v := reflect.ValueOf(n).Elem()
1179 t := reflect.TypeOf(n).Elem()
1181 for i := 0; i < nf; i++ {
1184 if tf.PkgPath != "" {
1185 // skip unexported field - Interface will fail
1188 switch tf.Type.Kind() {
1189 case reflect.Interface, reflect.Ptr, reflect.Slice:
1194 name := strings.TrimSuffix(tf.Name, "_")
1195 // Do not bother with field name header lines for the
1196 // most common positional arguments: unary, binary expr,
1197 // index expr, send stmt, go and defer call expression.
1199 case "X", "Y", "Index", "Chan", "Value", "Call":
1202 switch val := vf.Interface().(type) {
1206 fmt.Fprintf(w, "%+v-%s", n.Op(), name)
1208 dumpNode(w, val, depth+1)
1215 fmt.Fprintf(w, "%+v-%s", n.Op(), name)
1217 dumpNodes(w, val, depth+1)
1219 if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
1225 fmt.Fprintf(w, "%+v-%s", n.Op(), name)
1227 for i, n := 0, vf.Len(); i < n; i++ {
1228 dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
1235 var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
1237 func dumpNodes(w io.Writer, list Nodes, depth int) {
1239 fmt.Fprintf(w, " <nil>")
1243 for _, n := range list {
1244 dumpNode(w, n, depth)