]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: refactor constant rewriting
authorMatthew Dempsky <mdempsky@google.com>
Sat, 31 Mar 2018 23:49:07 +0000 (16:49 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 2 Apr 2018 04:09:29 +0000 (04:09 +0000)
Extract all rewrite-to-OLITERAL expressions to use a single setconst
helper function.

Does not pass toolstash-check for two reasons:

1) We now consistently clear Left/Right/etc when rewriting Nodes into
OLITERALs, which results in their inlining complexity being correctly
computed. So more functions can now be inlined.

2) We preserve Pos, so PC line tables change somewhat.

Change-Id: I2b5c293bee7c69c2ccd704677f5aba4ec40e3155
Reviewed-on: https://go-review.googlesource.com/103860
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/walk.go

index 8422eec17e7405b02a20bf506c9aaefbb26028ea..aad3db9b7771d573d77b55048bf4e01401d2b7f9 100644 (file)
@@ -6,7 +6,6 @@ package gc
 
 import (
        "cmd/compile/internal/types"
-       "cmd/internal/src"
        "math/big"
        "strings"
 )
@@ -564,8 +563,8 @@ func overflow(v Val, t *types.Type) bool {
                return false
        }
 
-       // Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
-       if t.Etype == TUNSAFEPTR {
+       // Only uintptrs may be converted to pointers, which cannot overflow.
+       if t.IsPtr() || t.IsUnsafePtr() {
                return false
        }
 
@@ -610,18 +609,6 @@ func Isconst(n *Node, ct Ctype) bool {
        return t == ct || (ct == CTINT && t == CTRUNE)
 }
 
-func saveorig(n *Node) *Node {
-       if n == n.Orig {
-               // duplicate node for n->orig.
-               n1 := nod(OLITERAL, nil, nil)
-
-               n.Orig = n1
-               *n1 = *n
-       }
-
-       return n.Orig
-}
-
 // if n is constant, rewrite as OLITERAL node.
 func evconst(n *Node) {
        // pick off just the opcodes that can be
@@ -745,20 +732,13 @@ func evconst(n *Node) {
 
        nr := n.Right
        var rv Val
-       var lno src.XPos
        var wr types.EType
        var ctype uint32
        var v Val
-       var norig *Node
-       var nn *Node
        if nr == nil {
                // copy numeric value to avoid modifying
                // nl, in case someone still refers to it (e.g. iota).
-               v = nl.Val()
-
-               if wl == TIDEAL {
-                       v = copyval(v)
-               }
+               v = copyval(nl.Val())
 
                // rune values are int values for the purpose of constant folding.
                ctype = uint32(v.Ctype())
@@ -900,12 +880,7 @@ func evconst(n *Node) {
 
        // copy numeric value to avoid modifying
        // n->left, in case someone still refers to it (e.g. iota).
-       v = nl.Val()
-
-       if wl == TIDEAL {
-               v = copyval(v)
-       }
-
+       v = copyval(nl.Val())
        rv = nr.Val()
 
        // convert to common ideal
@@ -1202,41 +1177,15 @@ func evconst(n *Node) {
        }
 
 ret:
-       norig = saveorig(n)
-       *n = *nl
-
-       // restore value of n->orig.
-       n.Orig = norig
-
-       n.SetVal(v)
-
-       // check range.
-       lno = setlineno(n)
-       overflow(v, n.Type)
-       lineno = lno
-
-       // truncate precision for non-ideal float.
-       if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL {
-               n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)})
-       }
+       setconst(n, v)
        return
 
 settrue:
-       nn = nodbool(true)
-       nn.Orig = saveorig(n)
-       if !iscmp[n.Op] {
-               nn.Type = nl.Type
-       }
-       *n = *nn
+       setconst(n, Val{true})
        return
 
 setfalse:
-       nn = nodbool(false)
-       nn.Orig = saveorig(n)
-       if !iscmp[n.Op] {
-               nn.Type = nl.Type
-       }
-       *n = *nn
+       setconst(n, Val{false})
        return
 
 illegal:
@@ -1246,6 +1195,42 @@ illegal:
        }
 }
 
+// setconst rewrites n as an OLITERAL with value v.
+func setconst(n *Node, v Val) {
+       // Ensure n.Orig still points to a semantically-equivalent
+       // expression after we rewrite n into a constant.
+       if n.Orig == n {
+               var ncopy Node
+               n.Orig = &ncopy
+               ncopy = *n
+       }
+
+       *n = Node{
+               Op:      OLITERAL,
+               Pos:     n.Pos,
+               Orig:    n.Orig,
+               Type:    n.Type,
+               Xoffset: BADWIDTH,
+       }
+       n.SetVal(v)
+
+       // Check range.
+       lno := setlineno(n)
+       overflow(v, n.Type)
+       lineno = lno
+
+       // Truncate precision for non-ideal float.
+       if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL {
+               n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)})
+       }
+}
+
+func setintconst(n *Node, v int64) {
+       u := new(Mpint)
+       u.SetInt64(v)
+       setconst(n, Val{u})
+}
+
 // nodlit returns a new untyped constant with value v.
 func nodlit(v Val) *Node {
        n := nod(OLITERAL, nil, nil)
@@ -1270,24 +1255,6 @@ func nodlit(v Val) *Node {
        return n
 }
 
-func nodcplxlit(r Val, i Val) *Node {
-       r = toflt(r)
-       i = toflt(i)
-
-       c := new(Mpcplx)
-       n := nod(OLITERAL, nil, nil)
-       n.Type = types.Types[TIDEAL]
-       n.SetVal(Val{c})
-
-       if r.Ctype() != CTFLT || i.Ctype() != CTFLT {
-               Fatalf("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype())
-       }
-
-       c.Real.Set(r.U.(*Mpflt))
-       c.Imag.Set(i.U.(*Mpflt))
-       return n
-}
-
 // idealkind returns a constant kind like consttype
 // but for an arbitrary "ideal" (untyped constant) expression.
 func idealkind(n *Node) Ctype {
index 071d7dc2a5d0482204b5d051ab24c4537f58bda0..a7e9f54b3fbd8e849cba61fe3c69749323aa70ad 100644 (file)
@@ -790,7 +790,8 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
                }
 
                var v Node
-               nodconst(&v, types.Types[TINT], t.NumElem())
+               v.Type = types.Types[TINT]
+               setintconst(&v, t.NumElem())
 
                nam.Xoffset += int64(array_array)
                gdata(&nam, nod(OADDR, vstat, nil), Widthptr)
index 7354625de05c8d3f2d6924d41694f63b7049ba01..0351de41d5236512d0b35c4e944bd86adddecf36 100644 (file)
@@ -364,15 +364,6 @@ func nodSym(op Op, left *Node, sym *types.Sym) *Node {
        return n
 }
 
-func saveorignode(n *Node) {
-       if n.Orig != nil {
-               return
-       }
-       norig := nod(n.Op, nil, nil)
-       *norig = *n
-       n.Orig = norig
-}
-
 // methcmp sorts methods by name with exported methods first,
 // and then non-exported methods by their package path.
 type methcmp []*types.Field
@@ -424,19 +415,6 @@ func nodfltconst(v *Mpflt) *Node {
        return nodlit(Val{u})
 }
 
-func nodconst(n *Node, t *types.Type, v int64) {
-       *n = Node{}
-       n.Op = OLITERAL
-       n.SetAddable(true)
-       n.SetVal(Val{new(Mpint)})
-       n.Val().U.(*Mpint).SetInt64(v)
-       n.Type = t
-
-       if t.IsFloat() {
-               Fatalf("nodconst: bad type %v", t)
-       }
-}
-
 func nodnil() *Node {
        return nodlit(Val{new(NilVal)})
 }
index 30fb185c9d498814fc1b0007e5a5562aa80247d9..9cbbc0b9b6d3486049bf723967b1afbbc6acef5a 100644 (file)
@@ -1294,12 +1294,10 @@ func typecheck1(n *Node, top int) *Node {
                        n.Type = nil
                        return n
                }
+               n.Type = types.Types[TUINTPTR]
 
                // any side effects disappear; ignore init
-               var r Node
-               nodconst(&r, types.Types[TUINTPTR], evalunsafe(n))
-               r.Orig = n
-               n = &r
+               setintconst(n, evalunsafe(n))
 
        case OCAP, OLEN:
                ok |= Erv
@@ -1330,7 +1328,9 @@ func typecheck1(n *Node, top int) *Node {
                        return n
                }
 
-               // result might be constant
+               n.Type = types.Types[TINT]
+
+               // Result might be constant.
                var res int64 = -1 // valid if >= 0
                switch t.Etype {
                case TSTRING:
@@ -1344,14 +1344,9 @@ func typecheck1(n *Node, top int) *Node {
                        }
                }
                if res >= 0 {
-                       var r Node
-                       nodconst(&r, types.Types[TINT], res)
-                       r.Orig = n
-                       n = &r
+                       setintconst(n, res)
                }
 
-               n.Type = types.Types[TINT]
-
        case OREAL, OIMAG:
                ok |= Erv
                if !onearg(n, "%v", n.Op) {
@@ -1367,11 +1362,21 @@ func typecheck1(n *Node, top int) *Node {
                        return n
                }
 
-               if t.Etype != TIDEAL && !t.IsComplex() {
+               // Determine result type.
+               et := t.Etype
+               switch et {
+               case TIDEAL:
+                       // result is ideal
+               case TCOMPLEX64:
+                       et = TFLOAT32
+               case TCOMPLEX128:
+                       et = TFLOAT64
+               default:
                        yyerror("invalid argument %L for %v", l, n.Op)
                        n.Type = nil
                        return n
                }
+               n.Type = types.Types[et]
 
                // if the argument is a constant, the result is a constant
                // (any untyped numeric constant can be represented as a
@@ -1400,24 +1405,8 @@ func typecheck1(n *Node, top int) *Node {
                                }
                                re = im
                        }
-                       orig := n
-                       n = nodfltconst(re)
-                       n.Orig = orig
-               }
-
-               // determine result type
-               et := t.Etype
-               switch et {
-               case TIDEAL:
-                       // result is ideal
-               case TCOMPLEX64:
-                       et = TFLOAT32
-               case TCOMPLEX128:
-                       et = TFLOAT64
-               default:
-                       Fatalf("unexpected Etype: %v\n", et)
+                       setconst(n, Val{re})
                }
-               n.Type = types.Types[et]
 
        case OCOMPLEX:
                ok |= Erv
@@ -1489,17 +1478,16 @@ func typecheck1(n *Node, top int) *Node {
                case TFLOAT64:
                        t = types.Types[TCOMPLEX128]
                }
+               n.Type = t
 
                if l.Op == OLITERAL && r.Op == OLITERAL {
                        // make it a complex literal
-                       r = nodcplxlit(l.Val(), r.Val())
-
-                       r.Orig = n
-                       n = r
+                       c := new(Mpcplx)
+                       c.Real.Set(toflt(l.Val()).U.(*Mpflt))
+                       c.Imag.Set(toflt(r.Val()).U.(*Mpflt))
+                       setconst(n, Val{c})
                }
 
-               n.Type = t
-
        case OCLOSE:
                if !onearg(n, "%v", n.Op) {
                        n.Type = nil
@@ -1701,7 +1689,6 @@ func typecheck1(n *Node, top int) *Node {
 
        case OCONV:
                ok |= Erv
-               saveorignode(n)
                checkwidth(n.Type) // ensure width is calculated for backend
                n.Left = typecheck(n.Left, Erv)
                n.Left = convlit1(n.Left, n.Type, true, noReuse)
@@ -1717,19 +1704,16 @@ func typecheck1(n *Node, top int) *Node {
                                yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
                                n.SetDiag(true)
                        }
-
                        n.Op = OCONV
+                       n.Type = nil
+                       return n
                }
 
                switch n.Op {
                case OCONVNOP:
                        if n.Left.Op == OLITERAL {
-                               r := nod(OXXX, nil, nil)
                                n.Op = OCONV
-                               n.Orig = r
-                               *r = *n
-                               n.Op = OLITERAL
-                               n.SetVal(n.Left.Val())
+                               setconst(n, n.Left.Val())
                        } else if t.Etype == n.Type.Etype {
                                switch t.Etype {
                                case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
index 7798a4f36409681cda0acd638314861c8b2d8a98..6b862d3bf14e276a8f050cf8cb09bd6b5a000c69 100644 (file)
@@ -548,7 +548,7 @@ opswitch:
                }
                if t.IsArray() {
                        safeexpr(n.Left, init)
-                       nodconst(n, n.Type, t.NumElem())
+                       setintconst(n, t.NumElem())
                        n.SetTypecheck(1)
                }