1
0
mirror of https://github.com/golang/go synced 2024-11-22 19:44:57 -07:00

[dev.regabi] cmd/compile: cleanup for concrete types - import/export

An automated rewrite will add concrete type assertions after
a test of n.Op(), when n can be safely type-asserted
(meaning, n is not reassigned a different type, n is not reassigned
and then used outside the scope of the type assertion,
and so on).

This sequence of CLs handles the code that the automated
rewrite does not: adding specific types to function arguments,
adjusting code not to call n.Left() etc when n may have multiple
representations, and so on.

This CL focuses on iimport.go and iexport.go.

Passes buildall w/ toolstash -cmp.

Change-Id: I63edee54991ae5d982e99efa7a2894478d511910
Reviewed-on: https://go-review.googlesource.com/c/go/+/277925
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-10 18:46:29 -05:00
parent aa55d4e54b
commit 5fe64298a4
4 changed files with 123 additions and 79 deletions

View File

@ -15,8 +15,11 @@ type exporter struct {
// markObject visits a reachable object. // markObject visits a reachable object.
func (p *exporter) markObject(n ir.Node) { func (p *exporter) markObject(n ir.Node) {
if n.Op() == ir.ONAME && n.Class() == ir.PFUNC { if n.Op() == ir.ONAME {
inlFlood(n.(*ir.Name)) n := n.(*ir.Name)
if n.Class() == ir.PFUNC {
inlFlood(n)
}
} }
p.markType(n.Type()) p.markType(n.Type())

View File

@ -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)
}

View File

@ -1069,7 +1069,7 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
} }
switch op := n.Op(); op { switch n.Op() {
case ir.OBLOCK: case ir.OBLOCK:
// No OBLOCK in export data. // No OBLOCK in export data.
// Inline content into this statement list, // Inline content into this statement list,
@ -1084,7 +1084,7 @@ func (w *exportWriter) stmt(n ir.Node) {
case ir.ODCL: case ir.ODCL:
w.op(ir.ODCL) w.op(ir.ODCL)
w.pos(n.Left().Pos()) w.pos(n.Left().Pos())
w.localName(n.Left()) w.localName(n.Left().(*ir.Name))
w.typ(n.Left().Type()) w.typ(n.Left().Type())
case ir.OAS: case ir.OAS:
@ -1099,9 +1099,10 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
case ir.OASOP: case ir.OASOP:
n := n.(*ir.AssignOpStmt)
w.op(ir.OASOP) w.op(ir.OASOP)
w.pos(n.Pos()) w.pos(n.Pos())
w.op(n.SubOp()) w.op(n.AsOp)
w.expr(n.Left()) w.expr(n.Left())
if w.bool(!n.Implicit()) { if w.bool(!n.Implicit()) {
w.expr(n.Right()) w.expr(n.Right())
@ -1122,7 +1123,7 @@ func (w *exportWriter) stmt(n ir.Node) {
// unreachable - generated by compiler for trampolin routines // unreachable - generated by compiler for trampolin routines
case ir.OGO, ir.ODEFER: case ir.OGO, ir.ODEFER:
w.op(op) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
@ -1148,8 +1149,15 @@ func (w *exportWriter) stmt(n ir.Node) {
w.expr(n.Right()) w.expr(n.Right())
w.stmtList(n.Body()) w.stmtList(n.Body())
case ir.OSELECT, ir.OSWITCH: case ir.OSELECT:
w.op(op) 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.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
w.exprsOrNil(n.Left(), nil) w.exprsOrNil(n.Left(), nil)
@ -1163,7 +1171,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.pos(n.Pos()) w.pos(n.Pos())
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL: case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
w.op(op) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
label := "" label := ""
if sym := n.Sym(); sym != nil { if sym := n.Sym(); sym != nil {
@ -1176,19 +1184,34 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
} }
func (w *exportWriter) caseList(sw ir.Node) { func isNamedTypeSwitch(n ir.Node) bool {
namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil 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))) w.uint64(uint64(len(cases)))
for _, cas := range cases { for _, cas := range cases {
if cas.Op() != ir.OCASE { cas := cas.(*ir.CaseStmt)
base.Fatalf("expected OCASE, got %v", cas)
}
w.pos(cas.Pos()) w.pos(cas.Pos())
w.stmtList(cas.List()) w.stmtList(cas.List())
if namedTypeSwitch { if namedTypeSwitch {
w.localName(cas.Rlist().First()) w.localName(cas.Rlist().First().(*ir.Name))
} }
w.stmtList(cas.Body()) w.stmtList(cas.Body())
} }
@ -1201,22 +1224,29 @@ func (w *exportWriter) exprList(list ir.Nodes) {
w.op(ir.OEND) w.op(ir.OEND)
} }
func (w *exportWriter) expr(n ir.Node) { func simplifyForExport(n ir.Node) ir.Node {
// from nodefmt (fmt.go) switch n.Op() {
// case ir.OPAREN:
// nodefmt reverts nodes back to their original - we don't need to do return simplifyForExport(n.Left())
// it because we are not bound to produce valid Go syntax when exporting case ir.ODEREF:
// if n.Implicit() {
// if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { return simplifyForExport(n.Left())
// n = n.Orig }
// } case ir.OADDR:
if n.Implicit() {
// from exprfmt (fmt.go) return simplifyForExport(n.Left())
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() 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 // expressions
// (somewhat closely following the structure of exprfmt in fmt.go) // (somewhat closely following the structure of exprfmt in fmt.go)
case ir.ONIL: case ir.ONIL:
@ -1243,6 +1273,7 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.ONAME: case ir.ONAME:
// Package scope name. // Package scope name.
n := n.(*ir.Name)
if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) { if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) {
w.op(ir.ONONAME) w.op(ir.ONONAME)
w.qualifiedIdent(n) w.qualifiedIdent(n)
@ -1291,7 +1322,7 @@ func (w *exportWriter) expr(n ir.Node) {
w.op(ir.OSTRUCTLIT) w.op(ir.OSTRUCTLIT)
w.pos(n.Pos()) w.pos(n.Pos())
w.typ(n.Type()) 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: case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
w.op(ir.OCOMPLIT) w.op(ir.OCOMPLIT)
@ -1349,7 +1380,7 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OCOPY, ir.OCOMPLEX: case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL) // treated like other builtin calls (see e.g., OREAL)
w.op(op) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) w.expr(n.Right())
@ -1361,20 +1392,21 @@ func (w *exportWriter) expr(n ir.Node) {
w.expr(n.Left()) w.expr(n.Left())
w.typ(n.Type()) 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: case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
w.op(op) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
if n.Left() != nil { w.expr(n.Left())
w.expr(n.Left()) w.op(ir.OEND)
w.op(ir.OEND)
} else { case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
w.exprList(n.List()) // emits terminating OEND w.op(n.Op())
} w.pos(n.Pos())
w.exprList(n.List()) // emits terminating OEND
// only append() calls may contain '...' arguments // only append() calls may contain '...' arguments
if op == ir.OAPPEND { if n.Op() == ir.OAPPEND {
w.bool(n.IsDDD()) w.bool(n.IsDDD())
} else if 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: 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()) w.bool(n.IsDDD())
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: 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.pos(n.Pos())
w.typ(n.Type()) w.typ(n.Type())
switch { switch {
default: default:
// empty list // empty list
w.op(ir.OEND) w.op(ir.OEND)
case n.List().Len() != 0: // pre-typecheck
w.exprList(n.List()) // emits terminating OEND
case n.Right() != nil: case n.Right() != nil:
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) w.expr(n.Right())
@ -1405,15 +1435,37 @@ func (w *exportWriter) expr(n ir.Node) {
} }
// unary expressions // unary expressions
case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV: case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
w.op(op) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) 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 // binary expressions
case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, 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.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR: ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR:
w.op(op) 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.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) 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())) w.uint64(uint64(list.Len()))
for _, n := range list.Slice() { for _, n := range list.Slice() {
n := n.(*ir.StructKeyExpr)
w.selector(n.Sym()) w.selector(n.Sym())
w.expr(n.Left()) 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 // Escape analysis happens after inline bodies are saved, but
// we're using the same ONAME nodes, so we might still see // we're using the same ONAME nodes, so we might still see
// PAUTOHEAP here. // PAUTOHEAP here.

View File

@ -753,7 +753,7 @@ func (r *importReader) stmtList() []ir.Node {
} }
func (r *importReader) caseList(sw ir.Node) []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()) cases := make([]ir.Node, r.uint64())
for i := range cases { for i := range cases {
@ -766,7 +766,7 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
caseVar := ir.NewNameAt(cas.Pos(), r.ident()) caseVar := ir.NewNameAt(cas.Pos(), r.ident())
declare(caseVar, dclcontext) declare(caseVar, dclcontext)
cas.PtrRlist().Set1(caseVar) cas.PtrRlist().Set1(caseVar)
caseVar.Defn = sw.Left() caseVar.Defn = sw.(*ir.SwitchStmt).Left()
} }
cas.PtrBody().Set(r.stmtList()) cas.PtrBody().Set(r.stmtList())
cases[i] = cas cases[i] = cas
@ -915,14 +915,14 @@ func (r *importReader) node() ir.Node {
return n 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: 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()) n.PtrList().Set(r.exprList())
if op == ir.OAPPEND { if op == ir.OAPPEND {
n.SetIsDDD(r.bool()) n.SetIsDDD(r.bool())
} }
return n return n
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: // case OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
// unreachable - mapped to OCALL case below by exporter // unreachable - mapped to OCALL case below by exporter
case ir.OCALL: case ir.OCALL:
@ -934,7 +934,7 @@ func (r *importReader) node() ir.Node {
return n return n
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: 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(ir.TypeNode(r.typ()))
n.PtrList().Append(r.exprList()...) n.PtrList().Append(r.exprList()...)
return n return n
@ -1042,8 +1042,7 @@ func (r *importReader) node() ir.Node {
case ir.OSELECT: case ir.OSELECT:
n := ir.NodAt(r.pos(), ir.OSELECT, nil, nil) n := ir.NodAt(r.pos(), ir.OSELECT, nil, nil)
n.PtrInit().Set(r.stmtList()) n.PtrInit().Set(r.stmtList())
left, _ := r.exprsOrNil() r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil.
n.SetLeft(left)
n.PtrList().Set(r.caseList(n)) n.PtrList().Set(r.caseList(n))
return n return n
@ -1110,3 +1109,12 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
} }
return 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
}