From 5024396563f9f544a3c6413026cf9b302fd83709 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 10 Dec 2020 18:47:58 -0500 Subject: [PATCH] [dev.regabi] cmd/compile: cleanup for concrete types - subr 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 subr.go. Passes buildall w/ toolstash -cmp. Change-Id: I435082167c91e20a4d490aa5d5945c7454f71d61 Reviewed-on: https://go-review.googlesource.com/c/go/+/277930 Trust: Russ Cox Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/subr.go | 119 ++++++++++++++++------- src/cmd/compile/internal/gc/typecheck.go | 2 +- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 37e49d0544..e519c57273 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -555,7 +555,7 @@ func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node { // backingArrayPtrLen extracts the pointer and length from a slice or string. // This constructs two nodes referring to n, so n must be a cheapexpr. -func backingArrayPtrLen(n ir.Node) (ptr, len ir.Node) { +func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) { var init ir.Nodes c := cheapexpr(n, &init) if c != n || init.Len() != 0 { @@ -567,9 +567,9 @@ func backingArrayPtrLen(n ir.Node) (ptr, len ir.Node) { } else { ptr.SetType(n.Type().Elem().PtrTo()) } - len = ir.Nod(ir.OLEN, n, nil) - len.SetType(types.Types[types.TINT]) - return ptr, len + length = ir.Nod(ir.OLEN, n, nil) + length.SetType(types.Types[types.TINT]) + return ptr, length } func syslook(name string) ir.Node { @@ -605,6 +605,10 @@ func calcHasCall(n ir.Node) bool { } switch n.Op() { + default: + base.Fatalf("calcHasCall %+v", n) + panic("unreachable") + case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OTYPE: if n.HasCall() { base.Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n) @@ -617,6 +621,7 @@ func calcHasCall(n ir.Node) bool { if instrumenting { return true } + return n.Left().HasCall() || n.Right().HasCall() case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR, ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD: // These ops might panic, make sure they are done @@ -625,27 +630,68 @@ func calcHasCall(n ir.Node) bool { // When using soft-float, these ops might be rewritten to function calls // so we ensure they are evaluated first. - case ir.OADD, ir.OSUB, ir.ONEG, ir.OMUL: + case ir.OADD, ir.OSUB, ir.OMUL: + if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) { + return true + } + return n.Left().HasCall() || n.Right().HasCall() + case ir.ONEG: if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) { return true } + return n.Left().HasCall() case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT: if thearch.SoftFloat && (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()]) { return true } + return n.Left().HasCall() || n.Right().HasCall() case ir.OCONV: if thearch.SoftFloat && ((isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) || (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()])) { return true } - } + return n.Left().HasCall() - if n.Left() != nil && n.Left().HasCall() { - return true - } - if n.Right() != nil && n.Right().HasCall() { - return true + case ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOPY, ir.OCOMPLEX, ir.OEFACE: + return n.Left().HasCall() || n.Right().HasCall() + + case ir.OAS: + return n.Left().HasCall() || n.Right() != nil && n.Right().HasCall() + + case ir.OADDR: + return n.Left().HasCall() + case ir.OPAREN: + return n.Left().HasCall() + case ir.OBITNOT, ir.ONOT, ir.OPLUS, ir.ORECV, + ir.OALIGNOF, ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.ONEW, + ir.OOFFSETOF, ir.OPANIC, ir.OREAL, ir.OSIZEOF, + ir.OCHECKNIL, ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.ONEWOBJ, ir.OSPTR, ir.OVARDEF, ir.OVARKILL, ir.OVARLIVE: + return n.Left().HasCall() + case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER: + return n.Left().HasCall() + + case ir.OGETG, ir.OCLOSUREREAD, ir.OMETHEXPR: + return false + + // TODO(rsc): These look wrong in various ways but are what calcHasCall has always done. + case ir.OADDSTR: + // TODO(rsc): This used to check left and right, which are not part of OADDSTR. + return false + case ir.OBLOCK: + // TODO(rsc): Surely the block's statements matter. + return false + case ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.OBYTES2STRTMP, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2BYTESTMP, ir.OSTR2RUNES, ir.ORUNESTR: + // TODO(rsc): Some conversions are themselves calls, no? + return n.Left().HasCall() + case ir.ODOTTYPE2: + // TODO(rsc): Shouldn't this be up with ODOTTYPE above? + return n.Left().HasCall() + case ir.OSLICEHEADER: + // TODO(rsc): What about len and cap? + return n.Left().HasCall() + case ir.OAS2DOTTYPE, ir.OAS2FUNC: + // TODO(rsc): Surely we need to check List and Rlist. + return false } - return false } func badtype(op ir.Op, tl, tr *types.Type) { @@ -727,26 +773,32 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node { case ir.ONAME, ir.OLITERAL, ir.ONIL: return n - case ir.ODOT, ir.OLEN, ir.OCAP: + case ir.OLEN, ir.OCAP: + l := safeexpr(n.Left(), init) + if l == n.Left() { + return n + } + a := ir.Copy(n).(*ir.UnaryExpr) + a.SetLeft(l) + return walkexpr(typecheck(a, ctxExpr), init) + + case ir.ODOT, ir.ODOTPTR: l := safeexpr(n.Left(), init) if l == n.Left() { return n } - r := ir.Copy(n) - r.SetLeft(l) - r = typecheck(r, ctxExpr) - r = walkexpr(r, init) - return r + a := ir.Copy(n).(*ir.SelectorExpr) + a.SetLeft(l) + return walkexpr(typecheck(a, ctxExpr), init) - case ir.ODOTPTR, ir.ODEREF: + case ir.ODEREF: l := safeexpr(n.Left(), init) if l == n.Left() { return n } - a := ir.Copy(n) + a := ir.Copy(n).(*ir.StarExpr) a.SetLeft(l) - a = walkexpr(a, init) - return a + return walkexpr(typecheck(a, ctxExpr), init) case ir.OINDEX, ir.OINDEXMAP: l := safeexpr(n.Left(), init) @@ -754,11 +806,10 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node { if l == n.Left() && r == n.Right() { return n } - a := ir.Copy(n) + a := ir.Copy(n).(*ir.IndexExpr) a.SetLeft(l) a.SetRight(r) - a = walkexpr(a, init) - return a + return walkexpr(typecheck(a, ctxExpr), init) case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT: if isStaticCompositeLiteral(n) { @@ -927,7 +978,7 @@ func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) ( // find missing fields that // will give shortest unique addressing. // modify the tree with missing type names. -func adddot(n ir.Node) ir.Node { +func adddot(n *ir.SelectorExpr) *ir.SelectorExpr { n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr)) if n.Left().Diag() { n.SetDiag(true) @@ -950,8 +1001,9 @@ func adddot(n ir.Node) ir.Node { case path != nil: // rebuild elided dots for c := len(path) - 1; c >= 0; c-- { - n.SetLeft(nodSym(ir.ODOT, n.Left(), path[c].field.Sym)) - n.Left().SetImplicit(true) + dot := nodSym(ir.ODOT, n.Left(), path[c].field.Sym) + dot.SetImplicit(true) + n.SetLeft(dot) } case ambig: base.Errorf("ambiguous selector %v", n) @@ -1179,12 +1231,12 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { // value for that function. if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) { // generate tail call: adjust pointer receiver and jump to embedded method. - dot = dot.Left() // skip final .M + left := dot.Left() // skip final .M // TODO(mdempsky): Remove dependency on dotlist. if !dotlist[0].field.Type.IsPtr() { - dot = nodAddr(dot) + left = ir.Nod(ir.OADDR, left, nil) } - as := ir.Nod(ir.OAS, nthis, convnop(dot, rcvr)) + as := ir.Nod(ir.OAS, nthis, convnop(left, rcvr)) fn.PtrBody().Append(as) fn.PtrBody().Append(nodSym(ir.ORETJMP, nil, methodSym(methodrcvr, method.Sym))) } else { @@ -1387,8 +1439,9 @@ func initExpr(init []ir.Node, n ir.Node) ir.Node { } if ir.MayBeShared(n) { // Introduce OCONVNOP to hold init list. - n = ir.Nod(ir.OCONVNOP, n, nil) - n.SetType(n.Left().Type()) + old := n + n = ir.Nod(ir.OCONVNOP, old, nil) + n.SetType(old.Type()) n.SetTypecheck(1) } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index ef1955e88b..70f05236c0 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -957,7 +957,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) { case ir.OXDOT, ir.ODOT: n := n.(*ir.SelectorExpr) if n.Op() == ir.OXDOT { - n = adddot(n).(*ir.SelectorExpr) + n = adddot(n) n.SetOp(ir.ODOT) if n.Left() == nil { n.SetType(nil) -- 2.48.1