From 3def15cd20dc136e033a5866086ce862dc36bd52 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 27 Feb 2019 17:34:07 -0800 Subject: [PATCH] cmd/compile: move all constant folding logic into evconst All setconst calls now happen within evconst. While here, get rid of callrecv, which (incompletely) duplicates the logic of hascallchan. Passes toolstash-check. Change-Id: Ic67b9dd2a1b397d4bc25e8c8b6f81daf4f6cfb75 Reviewed-on: https://go-review.googlesource.com/c/go/+/166980 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/const.go | 57 ++++++++++++++ src/cmd/compile/internal/gc/typecheck.go | 96 +----------------------- 2 files changed, 58 insertions(+), 95 deletions(-) diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index 0e6d838eaa..218d1d1d7f 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -631,6 +631,13 @@ func evconst(n *Node) { setconst(n, convlit1(nl, n.Type, true, false).Val()) } + case OCONVNOP: + if nl.Op == OLITERAL && nl.isGoConst() { + // set so n.Orig gets OCONV instead of OCONVNOP + n.Op = OCONV + setconst(n, nl.Val()) + } + case OBYTES2STR: // string([]byte(nil)) or string([]rune(nil)) if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL { @@ -664,6 +671,56 @@ func evconst(n *Node) { } else { n.List.Set(s) } + + case OCAP, OLEN: + switch nl.Type.Etype { + case TSTRING: + if Isconst(nl, CTSTR) { + setintconst(n, int64(len(nl.Val().U.(string)))) + } + case TARRAY: + if !hascallchan(nl) { + setintconst(n, nl.Type.NumElem()) + } + } + + case OALIGNOF, OOFFSETOF, OSIZEOF: + setintconst(n, evalunsafe(n)) + + case OREAL, OIMAG: + if nl.Op == OLITERAL { + var re, im *Mpflt + switch consttype(nl) { + case CTINT, CTRUNE: + re = newMpflt() + re.SetInt(nl.Val().U.(*Mpint)) + // im = 0 + case CTFLT: + re = nl.Val().U.(*Mpflt) + // im = 0 + case CTCPLX: + re = &nl.Val().U.(*Mpcplx).Real + im = &nl.Val().U.(*Mpcplx).Imag + default: + Fatalf("impossible") + } + if n.Op == OIMAG { + if im == nil { + im = newMpflt() + } + re = im + } + setconst(n, Val{re}) + } + + case OCOMPLEX: + if nl.Op == OLITERAL && nr.Op == OLITERAL { + // make it a complex literal + c := newMpcmplx() + c.Real.Set(toflt(nl.Val()).U.(*Mpflt)) + c.Imag.Set(toflt(nr.Val()).U.(*Mpflt)) + setconst(n, Val{c}) + } } } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 69ba9ef52a..8ae6c112b6 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -307,39 +307,6 @@ func typecheck(n *Node, top int) (res *Node) { return n } -// does n contain a call or receive operation? -func callrecv(n *Node) bool { - if n == nil { - return false - } - - switch n.Op { - case OCALL, - OCALLMETH, - OCALLINTER, - OCALLFUNC, - ORECV, - OCAP, - OLEN, - OCOPY, - ONEW, - OAPPEND, - ODELETE: - return true - } - - return callrecv(n.Left) || callrecv(n.Right) || callrecvlist(n.Ninit) || callrecvlist(n.Nbody) || callrecvlist(n.List) || callrecvlist(n.Rlist) -} - -func callrecvlist(l Nodes) bool { - for _, n := range l.Slice() { - if callrecv(n) { - return true - } - } - return false -} - // indexlit implements typechecking of untyped values as // array/slice indexes. It is almost equivalent to defaultlit // but also accepts untyped numeric values representable as @@ -1402,9 +1369,6 @@ func typecheck1(n *Node, top int) (res *Node) { } n.Type = types.Types[TUINTPTR] - // any side effects disappear; ignore init - setintconst(n, evalunsafe(n)) - case OCAP, OLEN: ok |= ctxExpr if !onearg(n, "%v", n.Op) { @@ -1436,23 +1400,6 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = types.Types[TINT] - // Result might be constant. - var res int64 = -1 // valid if >= 0 - switch t.Etype { - case TSTRING: - if Isconst(l, CTSTR) { - res = int64(len(l.Val().U.(string))) - } - - case TARRAY: - if !callrecv(l) { - res = t.NumElem() - } - } - if res >= 0 { - setintconst(n, res) - } - case OREAL, OIMAG: ok |= ctxExpr if !onearg(n, "%v", n.Op) { @@ -1484,36 +1431,6 @@ func typecheck1(n *Node, top int) (res *Node) { } 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 - // complex number) - if l.Op == OLITERAL { - var re, im *Mpflt - switch consttype(l) { - case CTINT, CTRUNE: - re = newMpflt() - re.SetInt(l.Val().U.(*Mpint)) - // im = 0 - case CTFLT: - re = l.Val().U.(*Mpflt) - // im = 0 - case CTCPLX: - re = &l.Val().U.(*Mpcplx).Real - im = &l.Val().U.(*Mpcplx).Imag - default: - yyerror("invalid argument %L for %v", l, n.Op) - n.Type = nil - return n - } - if n.Op == OIMAG { - if im == nil { - im = newMpflt() - } - re = im - } - setconst(n, Val{re}) - } - case OCOMPLEX: ok |= ctxExpr var r *Node @@ -1586,14 +1503,6 @@ func typecheck1(n *Node, top int) (res *Node) { } n.Type = t - if l.Op == OLITERAL && r.Op == OLITERAL { - // make it a complex literal - c := newMpcmplx() - c.Real.Set(toflt(l.Val()).U.(*Mpflt)) - c.Imag.Set(toflt(r.Val()).U.(*Mpflt)) - setconst(n, Val{c}) - } - case OCLOSE: if !onearg(n, "%v", n.Op) { n.Type = nil @@ -1817,10 +1726,7 @@ func typecheck1(n *Node, top int) (res *Node) { switch n.Op { case OCONVNOP: - if n.Left.Op == OLITERAL && n.isGoConst() { - n.Op = OCONV // set so n.Orig gets OCONV instead of OCONVNOP - setconst(n, n.Left.Val()) // convert n to OLITERAL with the given value - } else if t.Etype == n.Type.Etype { + if t.Etype == n.Type.Etype { switch t.Etype { case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128: // Floating point casts imply rounding and