mirror of
https://github.com/golang/go
synced 2024-11-23 05:00:07 -07:00
cmd/compile: remove typecheck.EvalConst
types2 has already done most of the constant folding parts. The only case left is unsafe.{Alignoff,Offsetof,Sizeof} with variable size argument, which is handled separately during typecheck. Change-Id: I8050b7613a16b19b91751726ac07253333177f73 Reviewed-on: https://go-review.googlesource.com/c/go/+/469595 Reviewed-by: Keith Randall <khr@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com> Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
13f0b8f421
commit
25bc96dbd2
@ -11,7 +11,6 @@ import (
|
|||||||
"internal/types/errors"
|
"internal/types/errors"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
@ -349,178 +348,6 @@ var tokenForOp = [...]token.Token{
|
|||||||
ir.ORSH: token.SHR,
|
ir.ORSH: token.SHR,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 ir.Node) ir.Node {
|
|
||||||
// Pick off just the opcodes that can be constant evaluated.
|
|
||||||
switch n.Op() {
|
|
||||||
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
|
|
||||||
n := n.(*ir.UnaryExpr)
|
|
||||||
nl := n.X
|
|
||||||
if nl.Op() == ir.OLITERAL {
|
|
||||||
var prec uint
|
|
||||||
if n.Type().IsUnsigned() {
|
|
||||||
prec = uint(n.Type().Size() * 8)
|
|
||||||
}
|
|
||||||
return OrigConst(n, constant.UnaryOp(tokenForOp[n.Op()], nl.Val(), prec))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
|
|
||||||
n := n.(*ir.BinaryExpr)
|
|
||||||
nl, nr := n.X, n.Y
|
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
|
||||||
rval := nr.Val()
|
|
||||||
|
|
||||||
// check for divisor underflow in complex division (see issue 20227)
|
|
||||||
if n.Op() == ir.ODIV && n.Type().IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
|
|
||||||
base.Errorf("complex division by zero")
|
|
||||||
n.SetType(nil)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
if (n.Op() == ir.ODIV || n.Op() == ir.OMOD) && constant.Sign(rval) == 0 {
|
|
||||||
base.Errorf("division by zero")
|
|
||||||
n.SetType(nil)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
tok := tokenForOp[n.Op()]
|
|
||||||
if n.Op() == ir.ODIV && n.Type().IsInteger() {
|
|
||||||
tok = token.QUO_ASSIGN // integer division
|
|
||||||
}
|
|
||||||
return OrigConst(n, constant.BinaryOp(nl.Val(), tok, rval))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OOROR, ir.OANDAND:
|
|
||||||
n := n.(*ir.LogicalExpr)
|
|
||||||
nl, nr := n.X, n.Y
|
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
|
||||||
return OrigConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
|
|
||||||
n := n.(*ir.BinaryExpr)
|
|
||||||
nl, nr := n.X, n.Y
|
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
|
||||||
return OrigBool(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OLSH, ir.ORSH:
|
|
||||||
n := n.(*ir.BinaryExpr)
|
|
||||||
nl, nr := n.X, n.Y
|
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
|
||||||
// shiftBound from go/types; "so we can express smallestFloat64" (see issue #44057)
|
|
||||||
const shiftBound = 1023 - 1 + 52
|
|
||||||
s, ok := constant.Uint64Val(nr.Val())
|
|
||||||
if !ok || s > shiftBound {
|
|
||||||
base.Errorf("invalid shift count %v", nr)
|
|
||||||
n.SetType(nil)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return OrigConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OCONV, ir.ORUNESTR:
|
|
||||||
n := n.(*ir.ConvExpr)
|
|
||||||
nl := n.X
|
|
||||||
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
|
||||||
return OrigConst(n, convertVal(nl.Val(), n.Type(), true))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OCONVNOP:
|
|
||||||
n := n.(*ir.ConvExpr)
|
|
||||||
nl := n.X
|
|
||||||
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
|
||||||
// set so n.Orig gets OCONV instead of OCONVNOP
|
|
||||||
n.SetOp(ir.OCONV)
|
|
||||||
return OrigConst(n, nl.Val())
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OADDSTR:
|
|
||||||
// Merge adjacent constants in the argument list.
|
|
||||||
n := n.(*ir.AddStringExpr)
|
|
||||||
s := n.List
|
|
||||||
need := 0
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.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, ir.StringVal(c))
|
|
||||||
}
|
|
||||||
return OrigConst(n, constant.MakeString(strings.Join(strs, "")))
|
|
||||||
}
|
|
||||||
newList := make([]ir.Node, 0, need)
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if ir.IsConst(s[i], constant.String) && i+1 < len(s) && ir.IsConst(s[i+1], constant.String) {
|
|
||||||
// merge from i up to but not including i2
|
|
||||||
var strs []string
|
|
||||||
i2 := i
|
|
||||||
for i2 < len(s) && ir.IsConst(s[i2], constant.String) {
|
|
||||||
strs = append(strs, ir.StringVal(s[i2]))
|
|
||||||
i2++
|
|
||||||
}
|
|
||||||
|
|
||||||
nl := ir.Copy(n).(*ir.AddStringExpr)
|
|
||||||
nl.List = s[i:i2]
|
|
||||||
newList = append(newList, OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
|
|
||||||
i = i2 - 1
|
|
||||||
} else {
|
|
||||||
newList = append(newList, s[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nn := ir.Copy(n).(*ir.AddStringExpr)
|
|
||||||
nn.List = newList
|
|
||||||
return nn
|
|
||||||
|
|
||||||
case ir.OCAP, ir.OLEN:
|
|
||||||
n := n.(*ir.UnaryExpr)
|
|
||||||
nl := n.X
|
|
||||||
switch nl.Type().Kind() {
|
|
||||||
case types.TSTRING:
|
|
||||||
if ir.IsConst(nl, constant.String) {
|
|
||||||
return OrigInt(n, int64(len(ir.StringVal(nl))))
|
|
||||||
}
|
|
||||||
case types.TARRAY:
|
|
||||||
if !anyCallOrChan(nl) {
|
|
||||||
return OrigInt(n, nl.Type().NumElem())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OREAL:
|
|
||||||
n := n.(*ir.UnaryExpr)
|
|
||||||
nl := n.X
|
|
||||||
if nl.Op() == ir.OLITERAL {
|
|
||||||
return OrigConst(n, constant.Real(nl.Val()))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OIMAG:
|
|
||||||
n := n.(*ir.UnaryExpr)
|
|
||||||
nl := n.X
|
|
||||||
if nl.Op() == ir.OLITERAL {
|
|
||||||
return OrigConst(n, constant.Imag(nl.Val()))
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OCOMPLEX:
|
|
||||||
n := n.(*ir.BinaryExpr)
|
|
||||||
nl, nr := n.X, n.Y
|
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
|
||||||
return OrigConst(n, makeComplex(nl.Val(), nr.Val()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeFloat64(f float64) constant.Value {
|
func makeFloat64(f float64) constant.Value {
|
||||||
if math.IsInf(f, 0) {
|
if math.IsInf(f, 0) {
|
||||||
base.Fatalf("infinity is not a valid constant")
|
base.Fatalf("infinity is not a valid constant")
|
||||||
@ -532,10 +359,6 @@ func makeComplex(real, imag constant.Value) constant.Value {
|
|||||||
return constant.BinaryOp(constant.ToFloat(real), token.ADD, constant.MakeImag(constant.ToFloat(imag)))
|
return constant.BinaryOp(constant.ToFloat(real), token.ADD, constant.MakeImag(constant.ToFloat(imag)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func square(x constant.Value) constant.Value {
|
|
||||||
return constant.BinaryOp(x, token.MUL, x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For matching historical "constant OP overflow" error messages.
|
// For matching historical "constant OP overflow" error messages.
|
||||||
// TODO(mdempsky): Replace with error messages like go/types uses.
|
// TODO(mdempsky): Replace with error messages like go/types uses.
|
||||||
var overflowNames = [...]string{
|
var overflowNames = [...]string{
|
||||||
@ -733,13 +556,6 @@ func callOrChan(n ir.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// anyCallOrChan reports whether n contains any calls or channel operations.
|
|
||||||
func anyCallOrChan(n ir.Node) bool {
|
|
||||||
return ir.Any(n, func(n ir.Node) bool {
|
|
||||||
return callOrChan(n)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// evalunsafe evaluates a package unsafe operation and returns the result.
|
// evalunsafe evaluates a package unsafe operation and returns the result.
|
||||||
func evalunsafe(n ir.Node) int64 {
|
func evalunsafe(n ir.Node) int64 {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
|
@ -355,10 +355,6 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
|
|||||||
types.CheckSize(t)
|
types.CheckSize(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t != nil {
|
|
||||||
n = EvalConst(n)
|
|
||||||
t = n.Type()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(rsc): Lots of the complexity here is because typecheck can
|
// TODO(rsc): Lots of the complexity here is because typecheck can
|
||||||
// see OTYPE, ONAME, and OLITERAL nodes multiple times.
|
// see OTYPE, ONAME, and OLITERAL nodes multiple times.
|
||||||
@ -516,9 +512,6 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
if t != nil {
|
if t != nil {
|
||||||
n.X, n.Y = l, r
|
n.X, n.Y = l, r
|
||||||
n.SetType(types.UntypedBool)
|
n.SetType(types.UntypedBool)
|
||||||
if con := EvalConst(n); con.Op() == ir.OLITERAL {
|
|
||||||
return con
|
|
||||||
}
|
|
||||||
n.X, n.Y = defaultlit2(l, r, true)
|
n.X, n.Y = defaultlit2(l, r, true)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
Loading…
Reference in New Issue
Block a user