diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 43c4ce7150f..31fd251c5e0 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -15,8 +15,11 @@ type exporter struct { // markObject visits a reachable object. func (p *exporter) markObject(n ir.Node) { - if n.Op() == ir.ONAME && n.Class() == ir.PFUNC { - inlFlood(n.(*ir.Name)) + if n.Op() == ir.ONAME { + n := n.(*ir.Name) + if n.Class() == ir.PFUNC { + inlFlood(n) + } } p.markType(n.Type()) diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go deleted file mode 100644 index 5a7018d8e61..00000000000 --- a/src/cmd/compile/internal/gc/bimport.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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. - -package gc - -import ( - "cmd/compile/internal/ir" - "cmd/compile/internal/types" - "cmd/internal/src" -) - -func npos(pos src.XPos, n ir.Node) ir.Node { - n.SetPos(pos) - return n -} - -func builtinCall(op ir.Op) ir.Node { - return ir.Nod(ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) -} diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index 14356013de8..eac9f29e655 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -1069,7 +1069,7 @@ func (w *exportWriter) stmt(n ir.Node) { } } - switch op := n.Op(); op { + switch n.Op() { case ir.OBLOCK: // No OBLOCK in export data. // Inline content into this statement list, @@ -1084,7 +1084,7 @@ func (w *exportWriter) stmt(n ir.Node) { case ir.ODCL: w.op(ir.ODCL) w.pos(n.Left().Pos()) - w.localName(n.Left()) + w.localName(n.Left().(*ir.Name)) w.typ(n.Left().Type()) case ir.OAS: @@ -1099,9 +1099,10 @@ func (w *exportWriter) stmt(n ir.Node) { } case ir.OASOP: + n := n.(*ir.AssignOpStmt) w.op(ir.OASOP) w.pos(n.Pos()) - w.op(n.SubOp()) + w.op(n.AsOp) w.expr(n.Left()) if w.bool(!n.Implicit()) { w.expr(n.Right()) @@ -1122,7 +1123,7 @@ func (w *exportWriter) stmt(n ir.Node) { // unreachable - generated by compiler for trampolin routines case ir.OGO, ir.ODEFER: - w.op(op) + w.op(n.Op()) w.pos(n.Pos()) w.expr(n.Left()) @@ -1148,8 +1149,15 @@ func (w *exportWriter) stmt(n ir.Node) { w.expr(n.Right()) w.stmtList(n.Body()) - case ir.OSELECT, ir.OSWITCH: - w.op(op) + case ir.OSELECT: + w.op(n.Op()) + w.pos(n.Pos()) + w.stmtList(n.Init()) + w.exprsOrNil(nil, nil) // TODO(rsc): Delete (and fix importer). + w.caseList(n) + + case ir.OSWITCH: + w.op(n.Op()) w.pos(n.Pos()) w.stmtList(n.Init()) w.exprsOrNil(n.Left(), nil) @@ -1163,7 +1171,7 @@ func (w *exportWriter) stmt(n ir.Node) { w.pos(n.Pos()) case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL: - w.op(op) + w.op(n.Op()) w.pos(n.Pos()) label := "" if sym := n.Sym(); sym != nil { @@ -1176,19 +1184,34 @@ func (w *exportWriter) stmt(n ir.Node) { } } -func (w *exportWriter) caseList(sw ir.Node) { - namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil +func isNamedTypeSwitch(n ir.Node) bool { + if n.Op() != ir.OSWITCH { + return false + } + sw := n.(*ir.SwitchStmt) + if sw.Left() == nil || sw.Left().Op() != ir.OTYPESW { + return false + } + guard := sw.Left().(*ir.TypeSwitchGuard) + return guard.Left() != nil +} - cases := sw.List().Slice() +func (w *exportWriter) caseList(sw ir.Node) { + namedTypeSwitch := isNamedTypeSwitch(sw) + + var cases []ir.Node + if sw.Op() == ir.OSWITCH { + cases = sw.(*ir.SwitchStmt).List().Slice() + } else { + cases = sw.(*ir.SelectStmt).List().Slice() + } w.uint64(uint64(len(cases))) for _, cas := range cases { - if cas.Op() != ir.OCASE { - base.Fatalf("expected OCASE, got %v", cas) - } + cas := cas.(*ir.CaseStmt) w.pos(cas.Pos()) w.stmtList(cas.List()) if namedTypeSwitch { - w.localName(cas.Rlist().First()) + w.localName(cas.Rlist().First().(*ir.Name)) } w.stmtList(cas.Body()) } @@ -1201,22 +1224,29 @@ func (w *exportWriter) exprList(list ir.Nodes) { w.op(ir.OEND) } -func (w *exportWriter) expr(n ir.Node) { - // from nodefmt (fmt.go) - // - // nodefmt reverts nodes back to their original - we don't need to do - // it because we are not bound to produce valid Go syntax when exporting - // - // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { - // n = n.Orig - // } - - // from exprfmt (fmt.go) - for n.Op() == ir.OPAREN || n.Implicit() && (n.Op() == ir.ODEREF || n.Op() == ir.OADDR || n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR) { - n = n.Left() +func simplifyForExport(n ir.Node) ir.Node { + switch n.Op() { + case ir.OPAREN: + return simplifyForExport(n.Left()) + case ir.ODEREF: + if n.Implicit() { + return simplifyForExport(n.Left()) + } + case ir.OADDR: + if n.Implicit() { + return simplifyForExport(n.Left()) + } + case ir.ODOT, ir.ODOTPTR: + if n.Implicit() { + return simplifyForExport(n.Left()) + } } + return n +} - switch op := n.Op(); op { +func (w *exportWriter) expr(n ir.Node) { + n = simplifyForExport(n) + switch n.Op() { // expressions // (somewhat closely following the structure of exprfmt in fmt.go) case ir.ONIL: @@ -1243,6 +1273,7 @@ func (w *exportWriter) expr(n ir.Node) { case ir.ONAME: // Package scope name. + n := n.(*ir.Name) if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) { w.op(ir.ONONAME) w.qualifiedIdent(n) @@ -1291,7 +1322,7 @@ func (w *exportWriter) expr(n ir.Node) { w.op(ir.OSTRUCTLIT) w.pos(n.Pos()) w.typ(n.Type()) - w.elemList(n.List()) // special handling of field names + w.fieldList(n.List()) // special handling of field names case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: w.op(ir.OCOMPLIT) @@ -1349,7 +1380,7 @@ func (w *exportWriter) expr(n ir.Node) { case ir.OCOPY, ir.OCOMPLEX: // treated like other builtin calls (see e.g., OREAL) - w.op(op) + w.op(n.Op()) w.pos(n.Pos()) w.expr(n.Left()) w.expr(n.Right()) @@ -1361,20 +1392,21 @@ func (w *exportWriter) expr(n ir.Node) { w.expr(n.Left()) w.typ(n.Type()) - case ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: - w.op(op) + case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC: + w.op(n.Op()) w.pos(n.Pos()) - if n.Left() != nil { - w.expr(n.Left()) - w.op(ir.OEND) - } else { - w.exprList(n.List()) // emits terminating OEND - } + w.expr(n.Left()) + w.op(ir.OEND) + + case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: + w.op(n.Op()) + w.pos(n.Pos()) + w.exprList(n.List()) // emits terminating OEND // only append() calls may contain '...' arguments - if op == ir.OAPPEND { + if n.Op() == ir.OAPPEND { w.bool(n.IsDDD()) } else if n.IsDDD() { - base.Fatalf("exporter: unexpected '...' with %v call", op) + base.Fatalf("exporter: unexpected '...' with %v call", n.Op()) } case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG: @@ -1386,15 +1418,13 @@ func (w *exportWriter) expr(n ir.Node) { w.bool(n.IsDDD()) case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: - w.op(op) // must keep separate from OMAKE for importer + w.op(n.Op()) // must keep separate from OMAKE for importer w.pos(n.Pos()) w.typ(n.Type()) switch { default: // empty list w.op(ir.OEND) - case n.List().Len() != 0: // pre-typecheck - w.exprList(n.List()) // emits terminating OEND case n.Right() != nil: w.expr(n.Left()) w.expr(n.Right()) @@ -1405,15 +1435,37 @@ func (w *exportWriter) expr(n ir.Node) { } // unary expressions - case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV: - w.op(op) + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: + w.op(n.Op()) w.pos(n.Pos()) w.expr(n.Left()) + case ir.OADDR: + w.op(n.Op()) + w.pos(n.Pos()) + w.expr(n.Left()) + + case ir.ODEREF: + w.op(n.Op()) + w.pos(n.Pos()) + w.expr(n.Left()) + + case ir.OSEND: + w.op(n.Op()) + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) + // binary expressions - case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, - ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR: - w.op(op) + case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: + w.op(n.Op()) + w.pos(n.Pos()) + w.expr(n.Left()) + w.expr(n.Right()) + + case ir.OANDAND, ir.OOROR: + w.op(n.Op()) w.pos(n.Pos()) w.expr(n.Left()) w.expr(n.Right()) @@ -1454,15 +1506,16 @@ func (w *exportWriter) exprsOrNil(a, b ir.Node) { } } -func (w *exportWriter) elemList(list ir.Nodes) { +func (w *exportWriter) fieldList(list ir.Nodes) { w.uint64(uint64(list.Len())) for _, n := range list.Slice() { + n := n.(*ir.StructKeyExpr) w.selector(n.Sym()) w.expr(n.Left()) } } -func (w *exportWriter) localName(n ir.Node) { +func (w *exportWriter) localName(n *ir.Name) { // Escape analysis happens after inline bodies are saved, but // we're using the same ONAME nodes, so we might still see // PAUTOHEAP here. diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index 1096d7988e3..154c4e3a843 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -753,7 +753,7 @@ func (r *importReader) stmtList() []ir.Node { } func (r *importReader) caseList(sw ir.Node) []ir.Node { - namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil + namedTypeSwitch := isNamedTypeSwitch(sw) cases := make([]ir.Node, r.uint64()) for i := range cases { @@ -766,7 +766,7 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node { caseVar := ir.NewNameAt(cas.Pos(), r.ident()) declare(caseVar, dclcontext) cas.PtrRlist().Set1(caseVar) - caseVar.Defn = sw.Left() + caseVar.Defn = sw.(*ir.SwitchStmt).Left() } cas.PtrBody().Set(r.stmtList()) cases[i] = cas @@ -915,14 +915,14 @@ func (r *importReader) node() ir.Node { return n case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: - n := npos(r.pos(), builtinCall(op)) + n := builtinCall(r.pos(), op) n.PtrList().Set(r.exprList()) if op == ir.OAPPEND { n.SetIsDDD(r.bool()) } return n - // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: + // case OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: // unreachable - mapped to OCALL case below by exporter case ir.OCALL: @@ -934,7 +934,7 @@ func (r *importReader) node() ir.Node { return n case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: - n := npos(r.pos(), builtinCall(ir.OMAKE)) + n := builtinCall(r.pos(), ir.OMAKE) n.PtrList().Append(ir.TypeNode(r.typ())) n.PtrList().Append(r.exprList()...) return n @@ -1042,8 +1042,7 @@ func (r *importReader) node() ir.Node { case ir.OSELECT: n := ir.NodAt(r.pos(), ir.OSELECT, nil, nil) n.PtrInit().Set(r.stmtList()) - left, _ := r.exprsOrNil() - n.SetLeft(left) + r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil. n.PtrList().Set(r.caseList(n)) return n @@ -1110,3 +1109,12 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) { } return } + +func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr { + return ir.NewCallExpr(pos, ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) +} + +func npos(pos src.XPos, n ir.Node) ir.Node { + n.SetPos(pos) + return n +}