From: Michael Munday Date: Tue, 3 Mar 2020 12:44:19 +0000 (+0000) Subject: cmd/compile: remove walkinrange optimization X-Git-Tag: go1.15beta1~946 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=24343cb88640ae1e7dbfc4ec2f3ae81fc0aa07c7;p=gostls13.git cmd/compile: remove walkinrange optimization The walkinrange optimization has been superseded by CL 165998. Has a small positive impact on binary sizes: compilecmp master -> HEAD master (e37cc29863): cmd/compile: optimize integer-in-range checks HEAD (1a70680a34): cmd/compile: remove walkinrange optimization platform: linux/amd64 file before after Δ % addr2line 4329144 4325048 -4096 -0.095% api 6060970 6056874 -4096 -0.068% asm 5196905 5192809 -4096 -0.079% cgo 4898769 4890577 -8192 -0.167% compile 20222193 20209713 -12480 -0.062% cover 5331580 5323388 -8192 -0.154% dist 3732778 3728682 -4096 -0.110% doc 4748488 4740296 -8192 -0.173% link 6707380 6695092 -12288 -0.183% nm 4278685 4274589 -4096 -0.096% pack 2305038 2300942 -4096 -0.178% pprof 14874834 14870738 -4096 -0.028% test2json 2849221 2845125 -4096 -0.144% vet 8393173 8384981 -8192 -0.098% go 15205572 15193284 -12288 -0.081% total 131812292 131709700 -102592 -0.078% Updates #30645. Change-Id: I42d74481652c90fef1a9bc58c70836e42c9b1c4b Reviewed-on: https://go-review.googlesource.com/c/go/+/221802 Run-TryBot: Michael Munday TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 9298d7b783..d468f241f9 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -565,7 +565,6 @@ opswitch: n.Right = walkexpr(n.Right, &ll) n.Right = addinit(n.Right, ll.Slice()) - n = walkinrange(n, init) case OPRINT, OPRINTN: n = walkprint(n, init) @@ -3523,133 +3522,6 @@ func (n *Node) isIntOrdering() bool { return n.Left.Type.IsInteger() && n.Right.Type.IsInteger() } -// walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10. -// n must be an OANDAND or OOROR node. -// The result of walkinrange MUST be assigned back to n, e.g. -// n.Left = walkinrange(n.Left) -func walkinrange(n *Node, init *Nodes) *Node { - // We are looking for something equivalent to a opl b OP b opr c, where: - // * a, b, and c have integer type - // * b is side-effect-free - // * opl and opr are each < or ≤ - // * OP is && - l := n.Left - r := n.Right - if !l.isIntOrdering() || !r.isIntOrdering() { - return n - } - - // Find b, if it exists, and rename appropriately. - // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right - // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c - a, opl, b := l.Left, l.Op, l.Right - x, opr, c := r.Left, r.Op, r.Right - for i := 0; ; i++ { - if samesafeexpr(b, x) { - break - } - if i == 3 { - // Tried all permutations and couldn't find an appropriate b == x. - return n - } - if i&1 == 0 { - a, opl, b = b, brrev(opl), a - } else { - x, opr, c = c, brrev(opr), x - } - } - - // If n.Op is ||, apply de Morgan. - // Negate the internal ops now; we'll negate the top level op at the end. - // Henceforth assume &&. - negateResult := n.Op == OOROR - if negateResult { - opl = brcom(opl) - opr = brcom(opr) - } - - cmpdir := func(o Op) int { - switch o { - case OLE, OLT: - return -1 - case OGE, OGT: - return +1 - } - Fatalf("walkinrange cmpdir %v", o) - return 0 - } - if cmpdir(opl) != cmpdir(opr) { - // Not a range check; something like b < a && b < c. - return n - } - - switch opl { - case OGE, OGT: - // We have something like a > b && b ≥ c. - // Switch and reverse ops and rename constants, - // to make it look like a ≤ b && b < c. - a, c = c, a - opl, opr = brrev(opr), brrev(opl) - } - - // We must ensure that c-a is non-negative. - // For now, require a and c to be constants. - // In the future, we could also support a == 0 and c == len/cap(...). - // Unfortunately, by this point, most len/cap expressions have been - // stored into temporary variables. - if !Isconst(a, CTINT) || !Isconst(c, CTINT) { - return n - } - - // Ensure that Int64() does not overflow on a and c (it'll happen - // for any const above 2**63; see issue #27143). - if !a.CanInt64() || !c.CanInt64() { - return n - } - - if opl == OLT { - // We have a < b && ... - // We need a ≤ b && ... to safely use unsigned comparison tricks. - // If a is not the maximum constant for b's type, - // we can increment a and switch to ≤. - if a.Int64() >= maxintval[b.Type.Etype].Int64() { - return n - } - a = nodintconst(a.Int64() + 1) - opl = OLE - } - - bound := c.Int64() - a.Int64() - if bound < 0 { - // Bad news. Something like 5 <= x && x < 3. - // Rare in practice, and we still need to generate side-effects, - // so just leave it alone. - return n - } - - // We have a ≤ b && b < c (or a ≤ b && b ≤ c). - // This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a), - // which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a), - // which is equivalent to uint(b-a) < uint(c-a). - ut := b.Type.ToUnsigned() - lhs := conv(nod(OSUB, b, a), ut) - rhs := nodintconst(bound) - if negateResult { - // Negate top level. - opr = brcom(opr) - } - cmp := nod(opr, lhs, rhs) - cmp.Pos = n.Pos - cmp = addinit(cmp, l.Ninit.Slice()) - cmp = addinit(cmp, r.Ninit.Slice()) - // Typecheck the AST rooted at cmp... - cmp = typecheck(cmp, ctxExpr) - // ...but then reset cmp's type to match n's type. - cmp.Type = n.Type - cmp = walkexpr(cmp, init) - return cmp -} - // return 1 if integer n must be in range [0, max), 0 otherwise func bounded(n *Node, max int64) bool { if n.Type == nil || !n.Type.IsInteger() {