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() {