mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: cleanup for concrete types - const
An automated rewrite will add concrete type assertions after a test of n.Op(), when n can be safely type-asserted (meaning, n is not reassigned a different type, n is not reassigned and then used outside the scope of the type assertion, and so on). This sequence of CLs handles the code that the automated rewrite does not: adding specific types to function arguments, adjusting code not to call n.Left() etc when n may have multiple representations, and so on. This CL focuses on const.go. Passes buildall w/ toolstash -cmp. Change-Id: I824f18fa0344ddde56df0522f9fa5e237114bbe2 Reviewed-on: https://go-review.googlesource.com/c/go/+/277927 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
389ae3d5ba
commit
42fec2ded4
1 changed files with 51 additions and 25 deletions
|
|
@ -162,6 +162,7 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n := n.(*ir.UnaryExpr)
|
||||||
n.SetLeft(convlit(n.Left(), ot))
|
n.SetLeft(convlit(n.Left(), ot))
|
||||||
if n.Left().Type() == nil {
|
if n.Left().Type() == nil {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
|
|
@ -177,14 +178,24 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetLeft(convlit(n.Left(), ot))
|
var l, r ir.Node
|
||||||
n.SetRight(convlit(n.Right(), ot))
|
switch n := n.(type) {
|
||||||
if n.Left().Type() == nil || n.Right().Type() == nil {
|
case *ir.BinaryExpr:
|
||||||
|
n.SetLeft(convlit(n.Left(), ot))
|
||||||
|
n.SetRight(convlit(n.Right(), ot))
|
||||||
|
l, r = n.Left(), n.Right()
|
||||||
|
case *ir.LogicalExpr:
|
||||||
|
n.SetLeft(convlit(n.Left(), ot))
|
||||||
|
n.SetRight(convlit(n.Right(), ot))
|
||||||
|
l, r = n.Left(), n.Right()
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Type() == nil || r.Type() == nil {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
if !types.Identical(n.Left().Type(), n.Right().Type()) {
|
if !types.Identical(l.Type(), r.Type()) {
|
||||||
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, n.Left().Type(), n.Right().Type())
|
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
@ -435,48 +446,56 @@ var tokenForOp = [...]token.Token{
|
||||||
// Otherwise, evalConst returns a new OLITERAL with the same value as n,
|
// Otherwise, evalConst returns a new OLITERAL with the same value as n,
|
||||||
// and with .Orig pointing back to n.
|
// and with .Orig pointing back to n.
|
||||||
func evalConst(n ir.Node) ir.Node {
|
func evalConst(n ir.Node) ir.Node {
|
||||||
nl, nr := n.Left(), n.Right()
|
|
||||||
|
|
||||||
// Pick off just the opcodes that can be constant evaluated.
|
// Pick off just the opcodes that can be constant evaluated.
|
||||||
switch op := n.Op(); op {
|
switch n.Op() {
|
||||||
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
|
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
|
||||||
|
nl := n.Left()
|
||||||
if nl.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL {
|
||||||
var prec uint
|
var prec uint
|
||||||
if n.Type().IsUnsigned() {
|
if n.Type().IsUnsigned() {
|
||||||
prec = uint(n.Type().Size() * 8)
|
prec = uint(n.Type().Size() * 8)
|
||||||
}
|
}
|
||||||
return origConst(n, constant.UnaryOp(tokenForOp[op], nl.Val(), prec))
|
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, ir.OOROR, ir.OANDAND:
|
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
|
||||||
|
nl, nr := n.Left(), n.Right()
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||||
rval := nr.Val()
|
rval := nr.Val()
|
||||||
|
|
||||||
// check for divisor underflow in complex division (see issue 20227)
|
// check for divisor underflow in complex division (see issue 20227)
|
||||||
if op == ir.ODIV && n.Type().IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
|
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")
|
base.Errorf("complex division by zero")
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
if (op == ir.ODIV || op == ir.OMOD) && constant.Sign(rval) == 0 {
|
if (n.Op() == ir.ODIV || n.Op() == ir.OMOD) && constant.Sign(rval) == 0 {
|
||||||
base.Errorf("division by zero")
|
base.Errorf("division by zero")
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := tokenForOp[op]
|
tok := tokenForOp[n.Op()]
|
||||||
if op == ir.ODIV && n.Type().IsInteger() {
|
if n.Op() == ir.ODIV && n.Type().IsInteger() {
|
||||||
tok = token.QUO_ASSIGN // integer division
|
tok = token.QUO_ASSIGN // integer division
|
||||||
}
|
}
|
||||||
return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
|
return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
|
case ir.OOROR, ir.OANDAND:
|
||||||
|
nl, nr := n.Left(), n.Right()
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||||
return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[op], nr.Val()))
|
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:
|
||||||
|
nl, nr := n.Left(), n.Right()
|
||||||
|
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||||
|
return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OLSH, ir.ORSH:
|
case ir.OLSH, ir.ORSH:
|
||||||
|
nl, nr := n.Left(), n.Right()
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||||
// shiftBound from go/types; "so we can express smallestFloat64"
|
// shiftBound from go/types; "so we can express smallestFloat64"
|
||||||
const shiftBound = 1023 - 1 + 52
|
const shiftBound = 1023 - 1 + 52
|
||||||
|
|
@ -486,15 +505,17 @@ func evalConst(n ir.Node) ir.Node {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[op], uint(s)))
|
return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OCONV, ir.ORUNESTR:
|
case ir.OCONV, ir.ORUNESTR:
|
||||||
|
nl := n.Left()
|
||||||
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
||||||
return origConst(n, convertVal(nl.Val(), n.Type(), true))
|
return origConst(n, convertVal(nl.Val(), n.Type(), true))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OCONVNOP:
|
case ir.OCONVNOP:
|
||||||
|
nl := n.Left()
|
||||||
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
|
||||||
// set so n.Orig gets OCONV instead of OCONVNOP
|
// set so n.Orig gets OCONV instead of OCONVNOP
|
||||||
n.SetOp(ir.OCONV)
|
n.SetOp(ir.OCONV)
|
||||||
|
|
@ -532,21 +553,21 @@ func evalConst(n ir.Node) ir.Node {
|
||||||
i2++
|
i2++
|
||||||
}
|
}
|
||||||
|
|
||||||
nl := ir.Copy(n)
|
nl := ir.Copy(n).(*ir.AddStringExpr)
|
||||||
nl.PtrList().Set(s[i:i2])
|
nl.PtrList().Set(s[i:i2])
|
||||||
nl = origConst(nl, constant.MakeString(strings.Join(strs, "")))
|
newList = append(newList, origConst(nl, constant.MakeString(strings.Join(strs, ""))))
|
||||||
newList = append(newList, nl)
|
|
||||||
i = i2 - 1
|
i = i2 - 1
|
||||||
} else {
|
} else {
|
||||||
newList = append(newList, s[i])
|
newList = append(newList, s[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = ir.Copy(n)
|
nn := ir.Copy(n).(*ir.AddStringExpr)
|
||||||
n.PtrList().Set(newList)
|
nn.PtrList().Set(newList)
|
||||||
return n
|
return nn
|
||||||
|
|
||||||
case ir.OCAP, ir.OLEN:
|
case ir.OCAP, ir.OLEN:
|
||||||
|
nl := n.Left()
|
||||||
switch nl.Type().Kind() {
|
switch nl.Type().Kind() {
|
||||||
case types.TSTRING:
|
case types.TSTRING:
|
||||||
if ir.IsConst(nl, constant.String) {
|
if ir.IsConst(nl, constant.String) {
|
||||||
|
|
@ -562,16 +583,19 @@ func evalConst(n ir.Node) ir.Node {
|
||||||
return origIntConst(n, evalunsafe(n))
|
return origIntConst(n, evalunsafe(n))
|
||||||
|
|
||||||
case ir.OREAL:
|
case ir.OREAL:
|
||||||
|
nl := n.Left()
|
||||||
if nl.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL {
|
||||||
return origConst(n, constant.Real(nl.Val()))
|
return origConst(n, constant.Real(nl.Val()))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OIMAG:
|
case ir.OIMAG:
|
||||||
|
nl := n.Left()
|
||||||
if nl.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL {
|
||||||
return origConst(n, constant.Imag(nl.Val()))
|
return origConst(n, constant.Imag(nl.Val()))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OCOMPLEX:
|
case ir.OCOMPLEX:
|
||||||
|
nl, nr := n.Left(), n.Right()
|
||||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||||
return origConst(n, makeComplex(nl.Val(), nr.Val()))
|
return origConst(n, makeComplex(nl.Val(), nr.Val()))
|
||||||
}
|
}
|
||||||
|
|
@ -829,8 +853,10 @@ type constSetKey struct {
|
||||||
//
|
//
|
||||||
// n must not be an untyped constant.
|
// n must not be an untyped constant.
|
||||||
func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) {
|
func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) {
|
||||||
if n.Op() == ir.OCONVIFACE && n.Implicit() {
|
if conv := n; conv.Op() == ir.OCONVIFACE {
|
||||||
n = n.Left()
|
if conv.Implicit() {
|
||||||
|
n = conv.Left()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isGoConst(n) {
|
if !isGoConst(n) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue