]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: replace evconst with non-mutating version
authorRuss Cox <rsc@golang.org>
Tue, 24 Nov 2020 14:37:54 +0000 (09:37 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 24 Nov 2020 20:58:42 +0000 (20:58 +0000)
evconst is one of the largest sources of Op rewrites,
which prevent separating different kinds of nodes
(in this case, arithmetic nodes and OLITERAL nodes).

The change in swt.go is necessary because otherwise
the syntax graph ends up containing that OLEN expression
multiple times, which violates the invariant that it's a tree
except for ONAME, OLITERAL, and OTYPE nodes.
(Before, the OLEN was overwritten by an OLITERAL, so the
invariant still held, but now that we don't overwrite it,
we need a different copy for each instance.)

Passes toolstash -cmp.

Change-Id: Ia004774ab6852fb384805d0f9f9f234b40842811
Reviewed-on: https://go-review.googlesource.com/c/go/+/272869
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/swt.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/walk.go

index ebf3896a0a9a3b29e35f6c0178cf5954845c493f..18d5feb81398dc08caa8c17df926d9bf7c01f0bd 100644 (file)
@@ -542,87 +542,105 @@ func Isconst(n *Node, ct constant.Kind) bool {
        return consttype(n) == ct
 }
 
-// evconst rewrites constant expressions into OLITERAL nodes.
-func evconst(n *Node) {
+// evalConst returns a constant-evaluated expression equivalent to n.
+// If n is not a constant, evalConst returns n.
+// Otherwise, evalConst returns a new OLITERAL with the same value as n,
+// and with .Orig pointing back to n.
+func evalConst(n *Node) *Node {
        nl, nr := n.Left, n.Right
 
        // Pick off just the opcodes that can be constant evaluated.
        switch op := n.Op; op {
        case OPLUS, ONEG, OBITNOT, ONOT:
                if nl.Op == OLITERAL {
-                       setconst(n, unaryOp(op, nl.Val(), n.Type))
+                       return origConst(n, unaryOp(op, nl.Val(), n.Type))
                }
 
        case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
                if nl.Op == OLITERAL && nr.Op == OLITERAL {
-                       setconst(n, binaryOp(nl.Val(), op, nr.Val()))
+                       return origConst(n, binaryOp(nl.Val(), op, nr.Val()))
                }
 
        case OEQ, ONE, OLT, OLE, OGT, OGE:
                if nl.Op == OLITERAL && nr.Op == OLITERAL {
-                       setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
+                       return origBoolConst(n, compareOp(nl.Val(), op, nr.Val()))
                }
 
        case OLSH, ORSH:
                if nl.Op == OLITERAL && nr.Op == OLITERAL {
-                       setconst(n, shiftOp(nl.Val(), op, nr.Val()))
+                       return origConst(n, shiftOp(nl.Val(), op, nr.Val()))
                }
 
        case OCONV, ORUNESTR:
                if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
-                       setconst(n, convertVal(nl.Val(), n.Type, true))
+                       return origConst(n, convertVal(nl.Val(), n.Type, true))
                }
 
        case OCONVNOP:
                if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
                        // set so n.Orig gets OCONV instead of OCONVNOP
                        n.Op = OCONV
-                       setconst(n, nl.Val())
+                       return origConst(n, nl.Val())
                }
 
        case OADDSTR:
                // Merge adjacent constants in the argument list.
                s := n.List.Slice()
-               for i1 := 0; i1 < len(s); i1++ {
-                       if Isconst(s[i1], constant.String) && i1+1 < len(s) && Isconst(s[i1+1], constant.String) {
-                               // merge from i1 up to but not including i2
+               need := 0
+               for i := 0; i < len(s); i++ {
+                       if i == 0 || !Isconst(s[i-1], constant.String) || !Isconst(s[i], constant.String) {
+                               // Can't merge s[i] into s[i-1]; need a slot in the list.
+                               need++
+                       }
+               }
+               if need == len(s) {
+                       return n
+               }
+               if need == 1 {
+                       var strs []string
+                       for _, c := range s {
+                               strs = append(strs, c.StringVal())
+                       }
+                       return origConst(n, Val{U: strings.Join(strs, "")})
+               }
+               newList := make([]*Node, 0, need)
+               for i := 0; i < len(s); i++ {
+                       if Isconst(s[i], constant.String) && i+1 < len(s) && Isconst(s[i+1], constant.String) {
+                               // merge from i up to but not including i2
                                var strs []string
-                               i2 := i1
+                               i2 := i
                                for i2 < len(s) && Isconst(s[i2], constant.String) {
                                        strs = append(strs, s[i2].StringVal())
                                        i2++
                                }
 
-                               nl := *s[i1]
-                               nl.Orig = &nl
-                               nl.SetVal(Val{strings.Join(strs, "")})
-                               s[i1] = &nl
-                               s = append(s[:i1+1], s[i2:]...)
+                               nl := origConst(s[i], Val{U: strings.Join(strs, "")})
+                               nl.Orig = nl // it's bigger than just s[i]
+                               newList = append(newList, nl)
+                               i = i2 - 1
+                       } else {
+                               newList = append(newList, s[i])
                        }
                }
 
-               if len(s) == 1 && Isconst(s[0], constant.String) {
-                       n.Op = OLITERAL
-                       n.SetVal(s[0].Val())
-                       n.List.Set(nil)
-               } else {
-                       n.List.Set(s)
-               }
+               n = n.copy()
+               n.List.Set(newList)
+               return n
 
        case OCAP, OLEN:
                switch nl.Type.Etype {
                case TSTRING:
                        if Isconst(nl, constant.String) {
-                               setintconst(n, int64(len(nl.StringVal())))
+                               return origIntConst(n, int64(len(nl.StringVal())))
                        }
                case TARRAY:
                        if !hascallchan(nl) {
-                               setintconst(n, nl.Type.NumElem())
+                               return origIntConst(n, nl.Type.NumElem())
                        }
                }
 
        case OALIGNOF, OOFFSETOF, OSIZEOF:
-               setintconst(n, evalunsafe(n))
+               return origIntConst(n, evalunsafe(n))
 
        case OREAL, OIMAG:
                if nl.Op == OLITERAL {
@@ -647,7 +665,7 @@ func evconst(n *Node) {
                                }
                                re = im
                        }
-                       setconst(n, Val{re})
+                       return origConst(n, Val{re})
                }
 
        case OCOMPLEX:
@@ -656,9 +674,11 @@ func evconst(n *Node) {
                        c := newMpcmplx()
                        c.Real.Set(toflt(nl.Val()).U.(*Mpflt))
                        c.Imag.Set(toflt(nr.Val()).U.(*Mpflt))
-                       setconst(n, Val{c})
+                       return origConst(n, Val{c})
                }
        }
+
+       return n
 }
 
 func match(x, y Val) (Val, Val) {
@@ -927,27 +947,21 @@ func shiftOp(x Val, op Op, y Val) Val {
        return Val{U: u}
 }
 
-// setconst rewrites n as an OLITERAL with value v.
-func setconst(n *Node, v Val) {
-       // If constant folding failed, mark n as broken and give up.
+// origConst returns an OLITERAL with orig n and value v.
+func origConst(n *Node, v Val) *Node {
+       // If constant folding was attempted (we were called)
+       // but it produced an invalid constant value,
+       // mark n as broken and give up.
        if v.U == nil {
                n.Type = nil
-               return
-       }
-
-       // Ensure n.Orig still points to a semantically-equivalent
-       // expression after we rewrite n into a constant.
-       if n.Orig == n {
-               n.Orig = n.sepcopy()
+               return n
        }
 
-       *n = Node{
-               Op:      OLITERAL,
-               Pos:     n.Pos,
-               Orig:    n.Orig,
-               Type:    n.Type,
-               Xoffset: BADWIDTH,
-       }
+       orig := n
+       n = nod(OLITERAL, nil, nil)
+       n.Orig = orig
+       n.Pos = orig.Pos
+       n.Type = orig.Type
        n.SetVal(v)
 
        // Check range.
@@ -965,6 +979,7 @@ func setconst(n *Node, v Val) {
                        n.SetVal(Val{trunccmplxlit(v.U.(*Mpcplx), n.Type)})
                }
        }
+       return n
 }
 
 func assertRepresents(t *types.Type, v Val) {
@@ -983,14 +998,14 @@ func represents(t *types.Type, v Val) bool {
        return t == vt || (t == types.UntypedRune && vt == types.UntypedInt)
 }
 
-func setboolconst(n *Node, v bool) {
-       setconst(n, Val{U: v})
+func origBoolConst(n *Node, v bool) *Node {
+       return origConst(n, Val{U: v})
 }
 
-func setintconst(n *Node, v int64) {
+func origIntConst(n *Node, v int64) *Node {
        u := new(Mpint)
        u.SetInt64(v)
-       setconst(n, Val{u})
+       return origConst(n, Val{u})
 }
 
 // nodlit returns a new untyped constant with value v.
index 068f1a34e1f5af3b8232a8638bd70e7f524c224c..8459bd7c181ef8ba2d0c65c11190531aec2f2dc9 100644 (file)
@@ -386,14 +386,13 @@ func (s *exprSwitch) flush() {
                runs = append(runs, cc[start:])
 
                // Perform two-level binary search.
-               nlen := nod(OLEN, s.exprname, nil)
                binarySearch(len(runs), &s.done,
                        func(i int) *Node {
-                               return nod(OLE, nlen, nodintconst(runLen(runs[i-1])))
+                               return nod(OLE, nod(OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1])))
                        },
                        func(i int, nif *Node) {
                                run := runs[i]
-                               nif.Left = nod(OEQ, nlen, nodintconst(runLen(run)))
+                               nif.Left = nod(OEQ, nod(OLEN, s.exprname, nil), nodintconst(runLen(run)))
                                s.search(run, &nif.Nbody)
                        },
                )
index 5cc7c8a34c4e00eefd67c567e385dea4d8e83476..e014a0ba2d7d7fd09116fc61540088f1109c0620 100644 (file)
@@ -776,7 +776,7 @@ func typecheck1(n *Node, top int) (res *Node) {
                }
 
                if iscmp[n.Op] {
-                       evconst(n)
+                       n = evalConst(n)
                        t = types.UntypedBool
                        if n.Op != OLITERAL {
                                l, r = defaultlit2(l, r, true)
@@ -786,12 +786,13 @@ func typecheck1(n *Node, top int) (res *Node) {
                }
 
                if et == TSTRING && n.Op == OADD {
-                       // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
-                       n.Op = OADDSTR
-
+                       // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
                        if l.Op == OADDSTR {
-                               n.List.Set(l.List.Slice())
+                               orig := n
+                               n = l
+                               n.Pos = orig.Pos
                        } else {
+                               n = nodl(n.Pos, OADDSTR, nil, nil)
                                n.List.Set1(l)
                        }
                        if r.Op == OADDSTR {
@@ -799,8 +800,6 @@ func typecheck1(n *Node, top int) (res *Node) {
                        } else {
                                n.List.Append(r)
                        }
-                       n.Left = nil
-                       n.Right = nil
                }
 
                if (op == ODIV || op == OMOD) && Isconst(r, constant.Int) {
@@ -2091,7 +2090,7 @@ func typecheck1(n *Node, top int) (res *Node) {
                }
        }
 
-       evconst(n)
+       n = evalConst(n)
        if n.Op == OTYPE && top&ctxType == 0 {
                if !n.Type.Broke() {
                        yyerror("type %v is not an expression", n.Type)
index 7bf5281a67308a674d31302c377e4035e8b2d419..9971fb0c0dd7f9fd7827e7c645c7e7766086ef17 100644 (file)
@@ -513,7 +513,7 @@ opswitch:
                }
                if t.IsArray() {
                        safeexpr(n.Left, init)
-                       setintconst(n, t.NumElem())
+                       n = origIntConst(n, t.NumElem())
                        n.SetTypecheck(1)
                }
 
@@ -1580,7 +1580,7 @@ opswitch:
        // walk of y%1 may have replaced it by 0.
        // Check whether n with its updated args is itself now a constant.
        t := n.Type
-       evconst(n)
+       n = evalConst(n)
        if n.Type != t {
                Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type)
        }