mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
cmd/compile: refactor constant rewriting
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>
This commit is contained in:
parent
3c588b3fe7
commit
0250ef910f
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)})
|
||||
}
|
||||
|
@ -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,25 +1405,9 @@ func typecheck1(n *Node, top int) *Node {
|
||||
}
|
||||
re = im
|
||||
}
|
||||
orig := n
|
||||
n = nodfltconst(re)
|
||||
n.Orig = orig
|
||||
setconst(n, Val{re})
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
n.Type = types.Types[et]
|
||||
|
||||
case OCOMPLEX:
|
||||
ok |= Erv
|
||||
var r *Node
|
||||
@ -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:
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user