From 42fec2ded44a1bedf739dbc2b33f1b144616ec4c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 10 Dec 2020 18:46:56 -0500 Subject: [PATCH] [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 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/const.go | 74 +++++++++++++++++++--------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index 1ef199c793..358eefd9bb 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -162,6 +162,7 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir break } + n := n.(*ir.UnaryExpr) n.SetLeft(convlit(n.Left(), ot)) if n.Left().Type() == nil { n.SetType(nil) @@ -177,14 +178,24 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir break } - n.SetLeft(convlit(n.Left(), ot)) - n.SetRight(convlit(n.Right(), ot)) - if n.Left().Type() == nil || n.Right().Type() == nil { + var l, r ir.Node + switch n := n.(type) { + 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) return n } - if !types.Identical(n.Left().Type(), n.Right().Type()) { - base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, n.Left().Type(), n.Right().Type()) + if !types.Identical(l.Type(), r.Type()) { + base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type()) n.SetType(nil) return n } @@ -435,48 +446,56 @@ var tokenForOp = [...]token.Token{ // 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 { - nl, nr := n.Left(), n.Right() - // 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: + nl := n.Left() if nl.Op() == ir.OLITERAL { var prec uint if n.Type().IsUnsigned() { 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 { rval := nr.Val() // 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") n.SetType(nil) 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") n.SetType(nil) return n } - tok := tokenForOp[op] - if op == ir.ODIV && n.Type().IsInteger() { + 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: + nl, nr := n.Left(), n.Right() + 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: + nl, nr := n.Left(), n.Right() if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { - return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[op], nr.Val())) + return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val())) } case ir.OLSH, ir.ORSH: + nl, nr := n.Left(), n.Right() if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { // shiftBound from go/types; "so we can express smallestFloat64" const shiftBound = 1023 - 1 + 52 @@ -486,15 +505,17 @@ func evalConst(n ir.Node) ir.Node { n.SetType(nil) 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: + nl := n.Left() if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL { return origConst(n, convertVal(nl.Val(), n.Type(), true)) } case ir.OCONVNOP: + nl := n.Left() if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL { // set so n.Orig gets OCONV instead of OCONVNOP n.SetOp(ir.OCONV) @@ -532,21 +553,21 @@ func evalConst(n ir.Node) ir.Node { i2++ } - nl := ir.Copy(n) + nl := ir.Copy(n).(*ir.AddStringExpr) nl.PtrList().Set(s[i:i2]) - nl = origConst(nl, constant.MakeString(strings.Join(strs, ""))) - newList = append(newList, nl) + newList = append(newList, origConst(nl, constant.MakeString(strings.Join(strs, "")))) i = i2 - 1 } else { newList = append(newList, s[i]) } } - n = ir.Copy(n) - n.PtrList().Set(newList) - return n + nn := ir.Copy(n).(*ir.AddStringExpr) + nn.PtrList().Set(newList) + return nn case ir.OCAP, ir.OLEN: + nl := n.Left() switch nl.Type().Kind() { case types.TSTRING: if ir.IsConst(nl, constant.String) { @@ -562,16 +583,19 @@ func evalConst(n ir.Node) ir.Node { return origIntConst(n, evalunsafe(n)) case ir.OREAL: + nl := n.Left() if nl.Op() == ir.OLITERAL { return origConst(n, constant.Real(nl.Val())) } case ir.OIMAG: + nl := n.Left() if nl.Op() == ir.OLITERAL { return origConst(n, constant.Imag(nl.Val())) } case ir.OCOMPLEX: + nl, nr := n.Left(), n.Right() if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { return origConst(n, makeComplex(nl.Val(), nr.Val())) } @@ -829,8 +853,10 @@ type constSetKey struct { // // n must not be an untyped constant. func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) { - if n.Op() == ir.OCONVIFACE && n.Implicit() { - n = n.Left() + if conv := n; conv.Op() == ir.OCONVIFACE { + if conv.Implicit() { + n = conv.Left() + } } if !isGoConst(n) { -- 2.48.1