mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: replace evconst with non-mutating version
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>
This commit is contained in:
parent
c22bc745c3
commit
6826287c6b
4 changed files with 76 additions and 63 deletions
|
|
@ -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
|
||||
return n
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
*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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue