]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: cleanup for concrete types - order
authorRuss Cox <rsc@golang.org>
Thu, 10 Dec 2020 23:45:35 +0000 (18:45 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 17 Dec 2020 04:42:58 +0000 (04:42 +0000)
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 order.go.

Passes buildall w/ toolstash -cmp.

Change-Id: Ib5731905a620175a6fe978f512da593e0dae9d87
Reviewed-on: https://go-review.googlesource.com/c/go/+/277922
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/ir/stmt.go

index e0c0cabcde3ffe7741ced3a4099e6eba628ad852..b0a9c9be3e1333e24566b3f667d1f0038bdadf45 100644 (file)
@@ -139,7 +139,7 @@ func (o *Order) cheapExpr(n ir.Node) ir.Node {
                if l == n.Left() {
                        return n
                }
-               a := ir.SepCopy(n)
+               a := ir.SepCopy(n).(*ir.UnaryExpr)
                a.SetLeft(l)
                return typecheck(a, ctxExpr)
        }
@@ -159,21 +159,39 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
        case ir.ONAME, ir.OLITERAL, ir.ONIL:
                return n
 
-       case ir.ODOT, ir.OLEN, ir.OCAP:
+       case ir.OLEN, ir.OCAP:
+               l := o.safeExpr(n.Left())
+               if l == n.Left() {
+                       return n
+               }
+               a := ir.SepCopy(n).(*ir.UnaryExpr)
+               a.SetLeft(l)
+               return typecheck(a, ctxExpr)
+
+       case ir.ODOT:
                l := o.safeExpr(n.Left())
                if l == n.Left() {
                        return n
                }
-               a := ir.SepCopy(n)
+               a := ir.SepCopy(n).(*ir.SelectorExpr)
+               a.SetLeft(l)
+               return typecheck(a, ctxExpr)
+
+       case ir.ODOTPTR:
+               l := o.cheapExpr(n.Left())
+               if l == n.Left() {
+                       return n
+               }
+               a := ir.SepCopy(n).(*ir.SelectorExpr)
                a.SetLeft(l)
                return typecheck(a, ctxExpr)
 
-       case ir.ODOTPTR, ir.ODEREF:
+       case ir.ODEREF:
                l := o.cheapExpr(n.Left())
                if l == n.Left() {
                        return n
                }
-               a := ir.SepCopy(n)
+               a := ir.SepCopy(n).(*ir.StarExpr)
                a.SetLeft(l)
                return typecheck(a, ctxExpr)
 
@@ -188,7 +206,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
                if l == n.Left() && r == n.Right() {
                        return n
                }
-               a := ir.SepCopy(n)
+               a := ir.SepCopy(n).(*ir.IndexExpr)
                a.SetLeft(l)
                a.SetRight(r)
                return typecheck(a, ctxExpr)
@@ -206,7 +224,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
 // because we emit explicit VARKILL instructions marking the end of those
 // temporaries' lifetimes.
 func isaddrokay(n ir.Node) bool {
-       return islvalue(n) && (n.Op() != ir.ONAME || n.Class() == ir.PEXTERN || ir.IsAutoTmp(n))
+       return islvalue(n) && (n.Op() != ir.ONAME || n.(*ir.Name).Class() == ir.PEXTERN || ir.IsAutoTmp(n))
 }
 
 // addrTemp ensures that n is okay to pass by address to runtime routines.
@@ -225,7 +243,7 @@ func (o *Order) addrTemp(n ir.Node) ir.Node {
                if s.out != nil {
                        base.Fatalf("staticassign of const generated code: %+v", n)
                }
-               vstat = typecheck(vstat, ctxExpr)
+               vstat = typecheck(vstat, ctxExpr).(*ir.Name)
                return vstat
        }
        if isaddrokay(n) {
@@ -267,6 +285,7 @@ func mapKeyReplaceStrConv(n ir.Node) bool {
                replaced = true
        case ir.OSTRUCTLIT:
                for _, elem := range n.List().Slice() {
+                       elem := elem.(*ir.StructKeyExpr)
                        if mapKeyReplaceStrConv(elem.Left()) {
                                replaced = true
                        }
@@ -274,7 +293,7 @@ func mapKeyReplaceStrConv(n ir.Node) bool {
        case ir.OARRAYLIT:
                for _, elem := range n.List().Slice() {
                        if elem.Op() == ir.OKEY {
-                               elem = elem.Right()
+                               elem = elem.(*ir.KeyExpr).Right()
                        }
                        if mapKeyReplaceStrConv(elem) {
                                replaced = true
@@ -337,60 +356,31 @@ func orderMakeSliceCopy(s []ir.Node) {
        if base.Flag.N != 0 || instrumenting {
                return
        }
-
-       if len(s) < 2 {
+       if len(s) < 2 || s[0] == nil || s[0].Op() != ir.OAS || s[1] == nil || s[1].Op() != ir.OCOPY {
                return
        }
 
-       asn := s[0]
-       copyn := s[1]
-
-       if asn == nil || asn.Op() != ir.OAS {
-               return
-       }
-       if asn.Left().Op() != ir.ONAME {
-               return
-       }
-       if ir.IsBlank(asn.Left()) {
-               return
-       }
-       maken := asn.Right()
-       if maken == nil || maken.Op() != ir.OMAKESLICE {
-               return
-       }
-       if maken.Esc() == EscNone {
-               return
-       }
-       if maken.Left() == nil || maken.Right() != nil {
-               return
-       }
-       if copyn.Op() != ir.OCOPY {
-               return
-       }
-       if copyn.Left().Op() != ir.ONAME {
-               return
-       }
-       if asn.Left().Sym() != copyn.Left().Sym() {
-               return
-       }
-       if copyn.Right().Op() != ir.ONAME {
+       as := s[0].(*ir.AssignStmt)
+       cp := s[1].(*ir.BinaryExpr)
+       if as.Right() == nil || as.Right().Op() != ir.OMAKESLICE || ir.IsBlank(as.Left()) ||
+               as.Left().Op() != ir.ONAME || cp.Left().Op() != ir.ONAME || cp.Right().Op() != ir.ONAME ||
+               as.Left().Name() != cp.Left().Name() || cp.Left().Name() == cp.Right().Name() {
+               // The line above this one is correct with the differing equality operators:
+               // we want as.X and cp.X to be the same name,
+               // but we want the initial data to be coming from a different name.
                return
        }
 
-       if copyn.Left().Sym() == copyn.Right().Sym() {
+       mk := as.Right().(*ir.MakeExpr)
+       if mk.Esc() == EscNone || mk.Left() == nil || mk.Right() != nil {
                return
        }
-
-       maken.SetOp(ir.OMAKESLICECOPY)
-       maken.SetRight(copyn.Right())
+       mk.SetOp(ir.OMAKESLICECOPY)
+       mk.SetRight(cp.Right())
        // Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
-       maken.SetBounded(maken.Left().Op() == ir.OLEN && samesafeexpr(maken.Left().Left(), copyn.Right()))
-
-       maken = typecheck(maken, ctxExpr)
-
+       mk.SetBounded(mk.Left().Op() == ir.OLEN && samesafeexpr(mk.Left().(*ir.UnaryExpr).Left(), cp.Right()))
+       as.SetRight(typecheck(mk, ctxExpr))
        s[1] = nil // remove separate copy call
-
-       return
 }
 
 // edge inserts coverage instrumentation for libfuzzer.
@@ -405,8 +395,7 @@ func (o *Order) edge() {
        counter.Name().SetLibfuzzerExtraCounter(true)
 
        // counter += 1
-       incr := ir.Nod(ir.OASOP, counter, nodintconst(1))
-       incr.SetSubOp(ir.OADD)
+       incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, nodintconst(1))
        o.append(incr)
 }
 
@@ -469,20 +458,34 @@ func (o *Order) init(n ir.Node) {
 
 // call orders the call expression n.
 // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-func (o *Order) call(n ir.Node) {
-       if n.Init().Len() > 0 {
-               // Caller should have already called o.init(n).
-               base.Fatalf("%v with unexpected ninit", n.Op())
+func (o *Order) call(nn ir.Node) {
+       if nn.Init().Len() > 0 {
+               // Caller should have already called o.init(nn).
+               base.Fatalf("%v with unexpected ninit", nn.Op())
        }
 
        // Builtin functions.
-       if n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER {
-               n.SetLeft(o.expr(n.Left(), nil))
-               n.SetRight(o.expr(n.Right(), nil))
-               o.exprList(n.List())
+       if nn.Op() != ir.OCALLFUNC && nn.Op() != ir.OCALLMETH && nn.Op() != ir.OCALLINTER {
+               switch n := nn.(type) {
+               default:
+                       base.Fatalf("unexpected call: %+v", n)
+               case *ir.UnaryExpr:
+                       n.SetLeft(o.expr(n.Left(), nil))
+               case *ir.ConvExpr:
+                       n.SetLeft(o.expr(n.Left(), nil))
+               case *ir.BinaryExpr:
+                       n.SetLeft(o.expr(n.Left(), nil))
+                       n.SetRight(o.expr(n.Right(), nil))
+               case *ir.MakeExpr:
+                       n.SetLeft(o.expr(n.Left(), nil))
+                       n.SetRight(o.expr(n.Right(), nil))
+               case *ir.CallExpr:
+                       o.exprList(n.List())
+               }
                return
        }
 
+       n := nn.(*ir.CallExpr)
        fixVariadicCall(n)
        n.SetLeft(o.expr(n.Left(), nil))
        o.exprList(n.List())
@@ -495,11 +498,13 @@ func (o *Order) call(n ir.Node) {
                // arrange for the pointer to be kept alive until the call returns,
                // by copying it into a temp and marking that temp
                // still alive when we pop the temp stack.
-               if arg.Op() == ir.OCONVNOP && arg.Left().Type().IsUnsafePtr() {
-                       x := o.copyExpr(arg.Left())
-                       arg.SetLeft(x)
-                       x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
-                       n.PtrBody().Append(typecheck(ir.Nod(ir.OVARLIVE, x, nil), ctxStmt))
+               if arg.Op() == ir.OCONVNOP {
+                       if arg.Left().Type().IsUnsafePtr() {
+                               x := o.copyExpr(arg.Left())
+                               arg.SetLeft(x)
+                               x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
+                               n.PtrBody().Append(typecheck(ir.Nod(ir.OVARLIVE, x, nil), ctxStmt))
+                       }
                }
        }
 
@@ -537,18 +542,14 @@ func (o *Order) mapAssign(n ir.Node) {
        default:
                base.Fatalf("order.mapAssign %v", n.Op())
 
-       case ir.OAS, ir.OASOP:
+       case ir.OAS:
                if n.Left().Op() == ir.OINDEXMAP {
-                       // Make sure we evaluate the RHS before starting the map insert.
-                       // We need to make sure the RHS won't panic.  See issue 22881.
-                       if n.Right().Op() == ir.OAPPEND {
-                               s := n.Right().List().Slice()[1:]
-                               for i, n := range s {
-                                       s[i] = o.cheapExpr(n)
-                               }
-                       } else {
-                               n.SetRight(o.cheapExpr(n.Right()))
-                       }
+                       n.SetRight(o.safeMapRHS(n.Right()))
+               }
+               o.out = append(o.out, n)
+       case ir.OASOP:
+               if n.Left().Op() == ir.OINDEXMAP {
+                       n.SetRight(o.safeMapRHS(n.Right()))
                }
                o.out = append(o.out, n)
 
@@ -557,6 +558,7 @@ func (o *Order) mapAssign(n ir.Node) {
                for i, m := range n.List().Slice() {
                        switch {
                        case m.Op() == ir.OINDEXMAP:
+                               m := m.(*ir.IndexExpr)
                                if !ir.IsAutoTmp(m.Left()) {
                                        m.SetLeft(o.copyExpr(m.Left()))
                                }
@@ -577,6 +579,19 @@ func (o *Order) mapAssign(n ir.Node) {
        }
 }
 
+func (o *Order) safeMapRHS(r ir.Node) ir.Node {
+       // Make sure we evaluate the RHS before starting the map insert.
+       // We need to make sure the RHS won't panic.  See issue 22881.
+       if r.Op() == ir.OAPPEND {
+               s := r.List().Slice()[1:]
+               for i, n := range s {
+                       s[i] = o.cheapExpr(n)
+               }
+               return r
+       }
+       return o.cheapExpr(r)
+}
+
 // stmt orders the statement n, appending to o.out.
 // Temporaries created during the statement are cleaned
 // up using VARKILL instructions as possible.
@@ -616,12 +631,15 @@ func (o *Order) stmt(n ir.Node) {
                        // makes sure there is nothing too deep being copied.
                        l1 := o.safeExpr(n.Left())
                        l2 := ir.DeepCopy(src.NoXPos, l1)
-                       if l1.Op() == ir.OINDEXMAP {
+                       if l2.Op() == ir.OINDEXMAP {
                                l2.SetIndexMapLValue(false)
                        }
                        l2 = o.copyExpr(l2)
                        r := o.expr(typecheck(ir.NewBinaryExpr(n.Pos(), n.SubOp(), l2, n.Right()), ctxExpr), nil)
-                       n = typecheck(ir.NodAt(n.Pos(), ir.OAS, l1, r), ctxStmt)
+                       as := typecheck(ir.NodAt(n.Pos(), ir.OAS, l1, r), ctxStmt)
+                       o.mapAssign(as)
+                       o.cleanTemp(t)
+                       return
                }
 
                o.mapAssign(n)
@@ -636,6 +654,7 @@ func (o *Order) stmt(n ir.Node) {
 
        // Special: avoid copy of func call n.Right
        case ir.OAS2FUNC:
+               n := n.(*ir.AssignListStmt)
                t := o.markTemp()
                o.exprList(n.List())
                o.init(n.Rlist().First())
@@ -650,11 +669,14 @@ func (o *Order) stmt(n ir.Node) {
        // OAS2MAPR: make sure key is addressable if needed,
        //           and make sure OINDEXMAP is not copied out.
        case ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OAS2MAPR:
+               n := n.(*ir.AssignListStmt)
                t := o.markTemp()
                o.exprList(n.List())
 
                switch r := n.Rlist().First(); r.Op() {
-               case ir.ODOTTYPE2, ir.ORECV:
+               case ir.ODOTTYPE2:
+                       r.SetLeft(o.expr(r.Left(), nil))
+               case ir.ORECV:
                        r.SetLeft(o.expr(r.Left(), nil))
                case ir.OINDEXMAP:
                        r.SetLeft(o.expr(r.Left(), nil))
@@ -692,17 +714,22 @@ func (o *Order) stmt(n ir.Node) {
                o.out = append(o.out, n)
                o.cleanTemp(t)
 
-       case ir.OCLOSE,
-               ir.OCOPY,
-               ir.OPRINT,
-               ir.OPRINTN,
-               ir.ORECOVER,
-               ir.ORECV:
+       case ir.OCLOSE, ir.ORECV:
+               t := o.markTemp()
+               n.SetLeft(o.expr(n.Left(), nil))
+               o.out = append(o.out, n)
+               o.cleanTemp(t)
+
+       case ir.OCOPY:
                t := o.markTemp()
                n.SetLeft(o.expr(n.Left(), nil))
                n.SetRight(o.expr(n.Right(), nil))
+               o.out = append(o.out, n)
+               o.cleanTemp(t)
+
+       case ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
+               t := o.markTemp()
                o.exprList(n.List())
-               o.exprList(n.Rlist())
                o.out = append(o.out, n)
                o.cleanTemp(t)
 
@@ -770,8 +797,9 @@ func (o *Order) stmt(n ir.Node) {
 
                // Mark []byte(str) range expression to reuse string backing storage.
                // It is safe because the storage cannot be mutated.
+               n := n.(*ir.RangeStmt)
                if n.Right().Op() == ir.OSTR2BYTES {
-                       n.Right().SetOp(ir.OSTR2BYTESTMP)
+                       n.Right().(*ir.ConvExpr).SetOp(ir.OSTR2BYTESTMP)
                }
 
                t := o.markTemp()
@@ -845,16 +873,14 @@ func (o *Order) stmt(n ir.Node) {
        case ir.OSELECT:
                t := o.markTemp()
 
-               for _, n2 := range n.List().Slice() {
-                       if n2.Op() != ir.OCASE {
-                               base.Fatalf("order select case %v", n2.Op())
-                       }
-                       r := n2.Left()
-                       setlineno(n2)
+               for _, cas := range n.List().Slice() {
+                       cas := cas.(*ir.CaseStmt)
+                       r := cas.Left()
+                       setlineno(cas)
 
                        // Append any new body prologue to ninit.
                        // The next loop will insert ninit into nbody.
-                       if n2.Init().Len() != 0 {
+                       if cas.Init().Len() != 0 {
                                base.Fatalf("order select ninit")
                        }
                        if r == nil {
@@ -866,26 +892,29 @@ func (o *Order) stmt(n ir.Node) {
                                base.Fatalf("unknown op in select %v", r.Op())
 
                        case ir.OSELRECV, ir.OSELRECV2:
-                               var dst, ok, recv ir.Node
+                               var dst, ok ir.Node
+                               var recv *ir.UnaryExpr
+                               var def bool
                                if r.Op() == ir.OSELRECV {
                                        // case x = <-c
                                        // case <-c (dst is ir.BlankNode)
-                                       dst, ok, recv = r.Left(), ir.BlankNode, r.Right()
+                                       def, dst, ok, recv = r.Colas(), r.Left(), ir.BlankNode, r.Right().(*ir.UnaryExpr)
                                } else {
+                                       r := r.(*ir.AssignListStmt)
                                        // case x, ok = <-c
-                                       dst, ok, recv = r.List().First(), r.List().Second(), r.Rlist().First()
+                                       def, dst, ok, recv = r.Colas(), r.List().First(), r.List().Second(), r.Rlist().First().(*ir.UnaryExpr)
                                }
 
                                // If this is case x := <-ch or case x, y := <-ch, the case has
                                // the ODCL nodes to declare x and y. We want to delay that
                                // declaration (and possible allocation) until inside the case body.
                                // Delete the ODCL nodes here and recreate them inside the body below.
-                               if r.Colas() {
+                               if def {
                                        init := r.Init().Slice()
-                                       if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].Left() == dst {
+                                       if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == dst {
                                                init = init[1:]
                                        }
-                                       if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].Left() == ok {
+                                       if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == ok {
                                                init = init[1:]
                                        }
                                        r.PtrInit().Set(init)
@@ -910,35 +939,36 @@ func (o *Order) stmt(n ir.Node) {
                                        // use channel element type for temporary to avoid conversions,
                                        // such as in case interfacevalue = <-intchan.
                                        // the conversion happens in the OAS instead.
-                                       if r.Colas() {
+                                       if def {
                                                dcl := ir.Nod(ir.ODCL, dst, nil)
-                                               n2.PtrInit().Append(typecheck(dcl, ctxStmt))
+                                               cas.PtrInit().Append(typecheck(dcl, ctxStmt))
                                        }
 
                                        tmp := o.newTemp(recv.Left().Type().Elem(), recv.Left().Type().Elem().HasPointers())
                                        as := ir.Nod(ir.OAS, dst, tmp)
-                                       n2.PtrInit().Append(typecheck(as, ctxStmt))
+                                       cas.PtrInit().Append(typecheck(as, ctxStmt))
                                        dst = tmp
                                }
                                if !ir.IsBlank(ok) {
-                                       if r.Colas() {
+                                       if def {
                                                dcl := ir.Nod(ir.ODCL, ok, nil)
-                                               n2.PtrInit().Append(typecheck(dcl, ctxStmt))
+                                               cas.PtrInit().Append(typecheck(dcl, ctxStmt))
                                        }
 
                                        tmp := o.newTemp(types.Types[types.TBOOL], false)
                                        as := ir.Nod(ir.OAS, ok, conv(tmp, ok.Type()))
-                                       n2.PtrInit().Append(typecheck(as, ctxStmt))
+                                       cas.PtrInit().Append(typecheck(as, ctxStmt))
                                        ok = tmp
                                }
 
                                if r.Op() == ir.OSELRECV {
                                        r.SetLeft(dst)
                                } else {
+                                       r := r.(*ir.AssignListStmt)
                                        r.List().SetIndex(0, dst)
                                        r.List().SetIndex(1, ok)
                                }
-                               orderBlock(n2.PtrInit(), o.free)
+                               orderBlock(cas.PtrInit(), o.free)
 
                        case ir.OSEND:
                                if r.Init().Len() != 0 {
@@ -962,14 +992,15 @@ func (o *Order) stmt(n ir.Node) {
                // Now that we have accumulated all the temporaries, clean them.
                // Also insert any ninit queued during the previous loop.
                // (The temporary cleaning must follow that ninit work.)
-               for _, n3 := range n.List().Slice() {
-                       orderBlock(n3.PtrBody(), o.free)
-                       n3.PtrBody().Prepend(o.cleanTempNoPop(t)...)
+               for _, cas := range n.List().Slice() {
+                       cas := cas.(*ir.CaseStmt)
+                       orderBlock(cas.PtrBody(), o.free)
+                       cas.PtrBody().Prepend(o.cleanTempNoPop(t)...)
 
                        // TODO(mdempsky): Is this actually necessary?
                        // walkselect appears to walk Ninit.
-                       n3.PtrBody().Prepend(n3.Init().Slice()...)
-                       n3.PtrInit().Set(nil)
+                       cas.PtrBody().Prepend(cas.Init().Slice()...)
+                       cas.PtrInit().Set(nil)
                }
 
                o.out = append(o.out, n)
@@ -998,6 +1029,7 @@ func (o *Order) stmt(n ir.Node) {
        // For now just clean all the temporaries at the end.
        // In practice that's fine.
        case ir.OSWITCH:
+               n := n.(*ir.SwitchStmt)
                if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
                        // Add empty "default:" case for instrumentation.
                        n.PtrList().Append(ir.Nod(ir.OCASE, nil, nil))
@@ -1006,9 +1038,7 @@ func (o *Order) stmt(n ir.Node) {
                t := o.markTemp()
                n.SetLeft(o.expr(n.Left(), nil))
                for _, ncas := range n.List().Slice() {
-                       if ncas.Op() != ir.OCASE {
-                               base.Fatalf("order switch case %v", ncas.Op())
-                       }
+                       ncas := ncas.(*ir.CaseStmt)
                        o.exprListInPlace(ncas.List())
                        orderBlock(ncas.PtrBody(), o.free)
                }
@@ -1020,11 +1050,9 @@ func (o *Order) stmt(n ir.Node) {
        base.Pos = lno
 }
 
-func hasDefaultCase(n ir.Node) bool {
+func hasDefaultCase(n *ir.SwitchStmt) bool {
        for _, ncas := range n.List().Slice() {
-               if ncas.Op() != ir.OCASE {
-                       base.Fatalf("expected case, found %v", ncas.Op())
-               }
+               ncas := ncas.(*ir.CaseStmt)
                if ncas.List().Len() == 0 {
                        return true
                }
@@ -1067,8 +1095,13 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
        if n == nil {
                return n
        }
-
        lno := setlineno(n)
+       n = o.expr1(n, lhs)
+       base.Pos = lno
+       return n
+}
+
+func (o *Order) expr1(n, lhs ir.Node) ir.Node {
        o.init(n)
 
        switch n.Op() {
@@ -1077,6 +1110,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        o.edit = o.exprNoLHS // create closure once
                }
                ir.EditChildren(n, o.edit)
+               return n
 
        // Addition of strings turns into a function call.
        // Allocate a temporary to hold the strings.
@@ -1111,6 +1145,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                                }
                        }
                }
+               return n
 
        case ir.OINDEXMAP:
                n.SetLeft(o.expr(n.Left(), nil))
@@ -1133,15 +1168,16 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                // key must be addressable
                n.SetRight(o.mapKeyTemp(n.Left().Type(), n.Right()))
                if needCopy {
-                       n = o.copyExpr(n)
+                       return o.copyExpr(n)
                }
+               return n
 
        // concrete type (not interface) argument might need an addressable
        // temporary to pass to the runtime conversion routine.
        case ir.OCONVIFACE:
                n.SetLeft(o.expr(n.Left(), nil))
                if n.Left().Type().IsInterface() {
-                       break
+                       return n
                }
                if _, needsaddr := convFuncName(n.Left().Type(), n.Type()); needsaddr || isStaticCompositeLiteral(n.Left()) {
                        // Need a temp if we need to pass the address to the conversion function.
@@ -1149,20 +1185,23 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        // whose address we can put directly in an interface (see OCONVIFACE case in walk).
                        n.SetLeft(o.addrTemp(n.Left()))
                }
+               return n
 
        case ir.OCONVNOP:
                if n.Type().IsKind(types.TUNSAFEPTR) && n.Left().Type().IsKind(types.TUINTPTR) && (n.Left().Op() == ir.OCALLFUNC || n.Left().Op() == ir.OCALLINTER || n.Left().Op() == ir.OCALLMETH) {
+                       call := n.Left().(*ir.CallExpr)
                        // When reordering unsafe.Pointer(f()) into a separate
                        // statement, the conversion and function call must stay
                        // together. See golang.org/issue/15329.
-                       o.init(n.Left())
-                       o.call(n.Left())
+                       o.init(call)
+                       o.call(call)
                        if lhs == nil || lhs.Op() != ir.ONAME || instrumenting {
-                               n = o.copyExpr(n)
+                               return o.copyExpr(n)
                        }
                } else {
                        n.SetLeft(o.expr(n.Left(), nil))
                }
+               return n
 
        case ir.OANDAND, ir.OOROR:
                // ... = LHS && RHS
@@ -1199,7 +1238,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        nif.PtrRlist().Set(gen)
                }
                o.out = append(o.out, nif)
-               n = r
+               return r
 
        case ir.OCALLFUNC,
                ir.OCALLINTER,
@@ -1222,27 +1261,31 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
 
                if isRuneCount(n) {
                        // len([]rune(s)) is rewritten to runtime.countrunes(s) later.
-                       n.Left().SetLeft(o.expr(n.Left().Left(), nil))
+                       conv := n.(*ir.UnaryExpr).Left().(*ir.ConvExpr)
+                       conv.SetLeft(o.expr(conv.Left(), nil))
                } else {
                        o.call(n)
                }
 
                if lhs == nil || lhs.Op() != ir.ONAME || instrumenting {
-                       n = o.copyExpr(n)
+                       return o.copyExpr(n)
                }
+               return n
 
        case ir.OAPPEND:
                // Check for append(x, make([]T, y)...) .
                if isAppendOfMake(n) {
-                       n.List().SetFirst(o.expr(n.List().First(), nil))                 // order x
-                       n.List().Second().SetLeft(o.expr(n.List().Second().Left(), nil)) // order y
+                       n.List().SetFirst(o.expr(n.List().First(), nil)) // order x
+                       mk := n.List().Second().(*ir.MakeExpr)
+                       mk.SetLeft(o.expr(mk.Left(), nil)) // order y
                } else {
                        o.exprList(n.List())
                }
 
                if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.List().First()) {
-                       n = o.copyExpr(n)
+                       return o.copyExpr(n)
                }
+               return n
 
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
                n.SetLeft(o.expr(n.Left(), nil))
@@ -1255,39 +1298,44 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                max = o.cheapExpr(max)
                n.SetSliceBounds(low, high, max)
                if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.Left()) {
-                       n = o.copyExpr(n)
+                       return o.copyExpr(n)
                }
+               return n
 
        case ir.OCLOSURE:
+               n := n.(*ir.ClosureExpr)
                if n.Transient() && len(n.Func().ClosureVars) > 0 {
                        prealloc[n] = o.newTemp(closureType(n), false)
                }
+               return n
 
-       case ir.OSLICELIT, ir.OCALLPART:
+       case ir.OCALLPART:
+               n := n.(*ir.CallPartExpr)
                n.SetLeft(o.expr(n.Left(), nil))
-               n.SetRight(o.expr(n.Right(), nil))
+               if n.Transient() {
+                       t := partialCallType(n)
+                       prealloc[n] = o.newTemp(t, false)
+               }
+               return n
+
+       case ir.OSLICELIT:
                o.exprList(n.List())
-               o.exprList(n.Rlist())
                if n.Transient() {
-                       var t *types.Type
-                       switch n.Op() {
-                       case ir.OSLICELIT:
-                               t = types.NewArray(n.Type().Elem(), ir.Int64Val(n.Right()))
-                       case ir.OCALLPART:
-                               t = partialCallType(n)
-                       }
+                       t := types.NewArray(n.Type().Elem(), ir.Int64Val(n.Right()))
                        prealloc[n] = o.newTemp(t, false)
                }
+               return n
 
        case ir.ODOTTYPE, ir.ODOTTYPE2:
                n.SetLeft(o.expr(n.Left(), nil))
                if !isdirectiface(n.Type()) || instrumenting {
-                       n = o.copyExprClear(n)
+                       return o.copyExprClear(n)
                }
+               return n
 
        case ir.ORECV:
                n.SetLeft(o.expr(n.Left(), nil))
-               n = o.copyExprClear(n)
+               return o.copyExprClear(n)
 
        case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
                n.SetLeft(o.expr(n.Left(), nil))
@@ -1300,10 +1348,10 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        // buffer during conversion. String comparison does not
                        // memorize the strings for later use, so it is safe.
                        if n.Left().Op() == ir.OBYTES2STR {
-                               n.Left().SetOp(ir.OBYTES2STRTMP)
+                               n.Left().(*ir.ConvExpr).SetOp(ir.OBYTES2STRTMP)
                        }
                        if n.Right().Op() == ir.OBYTES2STR {
-                               n.Right().SetOp(ir.OBYTES2STRTMP)
+                               n.Right().(*ir.ConvExpr).SetOp(ir.OBYTES2STRTMP)
                        }
 
                case t.IsStruct() || t.IsArray():
@@ -1312,6 +1360,8 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        n.SetLeft(o.addrTemp(n.Left()))
                        n.SetRight(o.addrTemp(n.Right()))
                }
+               return n
+
        case ir.OMAPLIT:
                // Order map by converting:
                //   map[int]int{
@@ -1330,11 +1380,9 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                // See issue 26552.
                entries := n.List().Slice()
                statics := entries[:0]
-               var dynamics []ir.Node
+               var dynamics []*ir.KeyExpr
                for _, r := range entries {
-                       if r.Op() != ir.OKEY {
-                               base.Fatalf("OMAPLIT entry not OKEY: %v\n", r)
-                       }
+                       r := r.(*ir.KeyExpr)
 
                        if !isStaticCompositeLiteral(r.Left()) || !isStaticCompositeLiteral(r.Right()) {
                                dynamics = append(dynamics, r)
@@ -1343,7 +1391,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
 
                        // Recursively ordering some static entries can change them to dynamic;
                        // e.g., OCONVIFACE nodes. See #31777.
-                       r = o.expr(r, nil)
+                       r = o.expr(r, nil).(*ir.KeyExpr)
                        if !isStaticCompositeLiteral(r.Left()) || !isStaticCompositeLiteral(r.Right()) {
                                dynamics = append(dynamics, r)
                                continue
@@ -1354,7 +1402,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                n.PtrList().Set(statics)
 
                if len(dynamics) == 0 {
-                       break
+                       return n
                }
 
                // Emit the creation of the map (with all its static entries).
@@ -1362,18 +1410,17 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                as := ir.Nod(ir.OAS, m, n)
                typecheck(as, ctxStmt)
                o.stmt(as)
-               n = m
 
                // Emit eval+insert of dynamic entries, one at a time.
                for _, r := range dynamics {
-                       as := ir.Nod(ir.OAS, ir.Nod(ir.OINDEX, n, r.Left()), r.Right())
+                       as := ir.Nod(ir.OAS, ir.Nod(ir.OINDEX, m, r.Left()), r.Right())
                        typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
                        o.stmt(as)
                }
+               return m
        }
 
-       base.Pos = lno
-       return n
+       // No return - type-assertions above. Each case must return for itself.
 }
 
 // as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
@@ -1384,7 +1431,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
 //     tmp1, tmp2, tmp3 = ...
 //     a, b, a = tmp1, tmp2, tmp3
 // This is necessary to ensure left to right assignment order.
-func (o *Order) as2(n ir.Node) {
+func (o *Order) as2(n *ir.AssignListStmt) {
        tmplist := []ir.Node{}
        left := []ir.Node{}
        for ni, l := range n.List().Slice() {
@@ -1406,7 +1453,7 @@ func (o *Order) as2(n ir.Node) {
 
 // okAs2 orders OAS2XXX with ok.
 // Just like as2, this also adds temporaries to ensure left-to-right assignment.
-func (o *Order) okAs2(n ir.Node) {
+func (o *Order) okAs2(n *ir.AssignListStmt) {
        var tmp1, tmp2 ir.Node
        if !ir.IsBlank(n.List().First()) {
                typ := n.Rlist().First().Type()
index b7d0c1adc45035ccc8c5f2aaeeb78253c2debd6c..0302ffcc949ec1936b142b2e9fcf258b296b7429 100644 (file)
@@ -137,8 +137,8 @@ type AssignOpStmt struct {
        IncDec bool // actually ++ or --
 }
 
-func NewAssignOpStmt(pos src.XPos, op Op, x, y Node) *AssignOpStmt {
-       n := &AssignOpStmt{AsOp: op, X: x, Y: y}
+func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
+       n := &AssignOpStmt{AsOp: asOp, X: x, Y: y}
        n.pos = pos
        n.op = OASOP
        return n